<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title></title>
        
        <meta name="robots" content="noindex" />
        
        


        <!-- Custom HTML head -->
        


        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        
        <link rel="icon" href="favicon.svg">
        
        
        <link rel="shortcut icon" href="favicon.png">
        
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        
        <link rel="stylesheet" href="fonts/fonts.css">
        

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        
        <link rel="stylesheet" href="theme/reference.css">
        

        
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="翻译说明.html">翻译说明</a></li><li class="chapter-item expanded affix "><a href="introduction.html">介绍</a></li><li class="chapter-item expanded "><a href="notation.html"><strong aria-hidden="true">1.</strong> 表义符</a></li><li class="chapter-item expanded "><a href="lexical-structure.html"><strong aria-hidden="true">2.</strong> 词法结构</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="input-format.html"><strong aria-hidden="true">2.1.</strong> 输入格式</a></li><li class="chapter-item expanded "><a href="keywords.html"><strong aria-hidden="true">2.2.</strong> 关键字</a></li><li class="chapter-item expanded "><a href="identifiers.html"><strong aria-hidden="true">2.3.</strong> 标识符</a></li><li class="chapter-item expanded "><a href="comments.html"><strong aria-hidden="true">2.4.</strong> 注释</a></li><li class="chapter-item expanded "><a href="whitespace.html"><strong aria-hidden="true">2.5.</strong> 空白符</a></li><li class="chapter-item expanded "><a href="tokens.html"><strong aria-hidden="true">2.6.</strong> token</a></li></ol></li><li class="chapter-item expanded "><a href="macros.html"><strong aria-hidden="true">3.</strong> 宏</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macros-by-example.html"><strong aria-hidden="true">3.1.</strong> 声明宏</a></li><li class="chapter-item expanded "><a href="procedural-macros.html"><strong aria-hidden="true">3.2.</strong> 过程宏</a></li></ol></li><li class="chapter-item expanded "><a href="crates-and-source-files.html"><strong aria-hidden="true">4.</strong> crate 和源文件</a></li><li class="chapter-item expanded "><a href="conditional-compilation.html"><strong aria-hidden="true">5.</strong> 条件编译</a></li><li class="chapter-item expanded "><a href="items.html"><strong aria-hidden="true">6.</strong> 程序项</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="items/modules.html"><strong aria-hidden="true">6.1.</strong> 模块</a></li><li class="chapter-item expanded "><a href="items/extern-crates.html"><strong aria-hidden="true">6.2.</strong> 外部crate</a></li><li class="chapter-item expanded "><a href="items/use-declarations.html"><strong aria-hidden="true">6.3.</strong> use声明</a></li><li class="chapter-item expanded "><a href="items/functions.html"><strong aria-hidden="true">6.4.</strong> 函数</a></li><li class="chapter-item expanded "><a href="items/type-aliases.html"><strong aria-hidden="true">6.5.</strong> 类型别名</a></li><li class="chapter-item expanded "><a href="items/structs.html"><strong aria-hidden="true">6.6.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="items/enumerations.html"><strong aria-hidden="true">6.7.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="items/unions.html"><strong aria-hidden="true">6.8.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="items/constant-items.html"><strong aria-hidden="true">6.9.</strong> 常量项</a></li><li class="chapter-item expanded "><a href="items/static-items.html"><strong aria-hidden="true">6.10.</strong> 静态项</a></li><li class="chapter-item expanded "><a href="items/traits.html"><strong aria-hidden="true">6.11.</strong> trait</a></li><li class="chapter-item expanded "><a href="items/implementations.html"><strong aria-hidden="true">6.12.</strong> 实现</a></li><li class="chapter-item expanded "><a href="items/external-blocks.html"><strong aria-hidden="true">6.13.</strong> 外部块</a></li><li class="chapter-item expanded "><a href="items/generics.html"><strong aria-hidden="true">6.14.</strong> 泛型参数</a></li><li class="chapter-item expanded "><a href="items/associated-items.html"><strong aria-hidden="true">6.15.</strong> 关联程序项</a></li></ol></li><li class="chapter-item expanded "><a href="attributes.html"><strong aria-hidden="true">7.</strong> 属性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="attributes/testing.html"><strong aria-hidden="true">7.1.</strong> 测试</a></li><li class="chapter-item expanded "><a href="attributes/derive.html"><strong aria-hidden="true">7.2.</strong> 派生</a></li><li class="chapter-item expanded "><a href="attributes/diagnostics.html"><strong aria-hidden="true">7.3.</strong> 诊断</a></li><li class="chapter-item expanded "><a href="attributes/codegen.html"><strong aria-hidden="true">7.4.</strong> 代码生成</a></li><li class="chapter-item expanded "><a href="attributes/limits.html"><strong aria-hidden="true">7.5.</strong> 极限值设置</a></li><li class="chapter-item expanded "><a href="attributes/type_system.html"><strong aria-hidden="true">7.6.</strong> 类型系统</a></li></ol></li><li class="chapter-item expanded "><a href="statements-and-expressions.html"><strong aria-hidden="true">8.</strong> 语句和表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="statements.html"><strong aria-hidden="true">8.1.</strong> 语句</a></li><li class="chapter-item expanded "><a href="expressions.html"><strong aria-hidden="true">8.2.</strong> 表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="expressions/literal-expr.html"><strong aria-hidden="true">8.2.1.</strong> 字面量表达式</a></li><li class="chapter-item expanded "><a href="expressions/path-expr.html"><strong aria-hidden="true">8.2.2.</strong> 路径表达式</a></li><li class="chapter-item expanded "><a href="expressions/block-expr.html"><strong aria-hidden="true">8.2.3.</strong> 块表达式</a></li><li class="chapter-item expanded "><a href="expressions/operator-expr.html"><strong aria-hidden="true">8.2.4.</strong> 运算符表达式</a></li><li class="chapter-item expanded "><a href="expressions/grouped-expr.html"><strong aria-hidden="true">8.2.5.</strong> 分组表达式</a></li><li class="chapter-item expanded "><a href="expressions/array-expr.html"><strong aria-hidden="true">8.2.6.</strong> 数组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/tuple-expr.html"><strong aria-hidden="true">8.2.7.</strong> 元组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/struct-expr.html"><strong aria-hidden="true">8.2.8.</strong> 结构体表达式</a></li><li class="chapter-item expanded "><a href="expressions/call-expr.html"><strong aria-hidden="true">8.2.9.</strong> 调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/method-call-expr.html"><strong aria-hidden="true">8.2.10.</strong> 方法调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/field-expr.html"><strong aria-hidden="true">8.2.11.</strong> 字段访问表达式</a></li><li class="chapter-item expanded "><a href="expressions/closure-expr.html"><strong aria-hidden="true">8.2.12.</strong> 闭包表达式</a></li><li class="chapter-item expanded "><a href="expressions/loop-expr.html"><strong aria-hidden="true">8.2.13.</strong> 循环表达式</a></li><li class="chapter-item expanded "><a href="expressions/range-expr.html"><strong aria-hidden="true">8.2.14.</strong> 区间表达式</a></li><li class="chapter-item expanded "><a href="expressions/if-expr.html"><strong aria-hidden="true">8.2.15.</strong> if 和 if let 表达式</a></li><li class="chapter-item expanded "><a href="expressions/match-expr.html"><strong aria-hidden="true">8.2.16.</strong> 匹配表达式</a></li><li class="chapter-item expanded "><a href="expressions/return-expr.html"><strong aria-hidden="true">8.2.17.</strong> 返回表达式</a></li><li class="chapter-item expanded "><a href="expressions/await-expr.html"><strong aria-hidden="true">8.2.18.</strong> 等待(await)表达式</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="patterns.html"><strong aria-hidden="true">9.</strong> 模式</a></li><li class="chapter-item expanded "><a href="type-system.html"><strong aria-hidden="true">10.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types.html"><strong aria-hidden="true">10.1.</strong> 类型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types/boolean.html"><strong aria-hidden="true">10.1.1.</strong> 布尔型</a></li><li class="chapter-item expanded "><a href="types/numeric.html"><strong aria-hidden="true">10.1.2.</strong> 数字型</a></li><li class="chapter-item expanded "><a href="types/textual.html"><strong aria-hidden="true">10.1.3.</strong> 字符型</a></li><li class="chapter-item expanded "><a href="types/never.html"><strong aria-hidden="true">10.1.4.</strong> never类型</a></li><li class="chapter-item expanded "><a href="types/tuple.html"><strong aria-hidden="true">10.1.5.</strong> 元组</a></li><li class="chapter-item expanded "><a href="types/array.html"><strong aria-hidden="true">10.1.6.</strong> 数组</a></li><li class="chapter-item expanded "><a href="types/slice.html"><strong aria-hidden="true">10.1.7.</strong> 切片</a></li><li class="chapter-item expanded "><a href="types/struct.html"><strong aria-hidden="true">10.1.8.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="types/enum.html"><strong aria-hidden="true">10.1.9.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="types/union.html"><strong aria-hidden="true">10.1.10.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="types/function-item.html"><strong aria-hidden="true">10.1.11.</strong> 函数项类型</a></li><li class="chapter-item expanded "><a href="types/closure.html"><strong aria-hidden="true">10.1.12.</strong> 闭包</a></li><li class="chapter-item expanded "><a href="types/pointer.html"><strong aria-hidden="true">10.1.13.</strong> 指针型</a></li><li class="chapter-item expanded "><a href="types/function-pointer.html"><strong aria-hidden="true">10.1.14.</strong> 函数指针</a></li><li class="chapter-item expanded "><a href="types/trait-object.html"><strong aria-hidden="true">10.1.15.</strong> trait对象</a></li><li class="chapter-item expanded "><a href="types/impl-trait.html"><strong aria-hidden="true">10.1.16.</strong> 实现trait</a></li><li class="chapter-item expanded "><a href="types/parameters.html"><strong aria-hidden="true">10.1.17.</strong> 类型参数</a></li><li class="chapter-item expanded "><a href="types/inferred.html"><strong aria-hidden="true">10.1.18.</strong> 推断型</a></li></ol></li><li class="chapter-item expanded "><a href="dynamically-sized-types.html"><strong aria-hidden="true">10.2.</strong> 动态尺寸类型(DST)</a></li><li class="chapter-item expanded "><a href="type-layout.html"><strong aria-hidden="true">10.3.</strong> 类型布局 </a></li><li class="chapter-item expanded "><a href="interior-mutability.html"><strong aria-hidden="true">10.4.</strong> 内部可变性</a></li><li class="chapter-item expanded "><a href="subtyping.html"><strong aria-hidden="true">10.5.</strong> 子类型和型变</a></li><li class="chapter-item expanded "><a href="trait-bounds.html"><strong aria-hidden="true">10.6.</strong> trait约束及其生存期约束</a></li><li class="chapter-item expanded "><a href="type-coercions.html"><strong aria-hidden="true">10.7.</strong> 类型自动强转</a></li><li class="chapter-item expanded "><a href="destructors.html"><strong aria-hidden="true">10.8.</strong> 析构函数</a></li><li class="chapter-item expanded "><a href="lifetime-elision.html"><strong aria-hidden="true">10.9.</strong> 生存期省略</a></li></ol></li><li class="chapter-item expanded "><a href="special-types-and-traits.html"><strong aria-hidden="true">11.</strong> 特殊类型和 trait</a></li><li class="chapter-item expanded "><a href="names.html"><strong aria-hidden="true">12.</strong> 名称</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="names/namespaces.html"><strong aria-hidden="true">12.1.</strong> 命名空间</a></li><li class="chapter-item expanded "><a href="names/scopes.html"><strong aria-hidden="true">12.2.</strong> 作用域</a></li><li class="chapter-item expanded "><a href="names/preludes.html"><strong aria-hidden="true">12.3.</strong> 预导入包</a></li><li class="chapter-item expanded "><a href="paths.html"><strong aria-hidden="true">12.4.</strong> 路径</a></li><li class="chapter-item expanded "><a href="names/name-resolution.html"><strong aria-hidden="true">12.5.</strong> 名称解析</a></li><li class="chapter-item expanded "><a href="visibility-and-privacy.html"><strong aria-hidden="true">12.6.</strong> 可见性与隐私权</a></li></ol></li><li class="chapter-item expanded "><a href="memory-model.html"><strong aria-hidden="true">13.</strong> 内存模型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="memory-allocation-and-lifetime.html"><strong aria-hidden="true">13.1.</strong> 内存分配和生存期</a></li><li class="chapter-item expanded "><a href="variables.html"><strong aria-hidden="true">13.2.</strong> 变量</a></li></ol></li><li class="chapter-item expanded "><a href="linkage.html"><strong aria-hidden="true">14.</strong> 链接(linkage)</a></li><li class="chapter-item expanded "><a href="unsafety.html"><strong aria-hidden="true">15.</strong> 非安全性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="unsafe-functions.html"><strong aria-hidden="true">15.1.</strong> 非安全函数</a></li><li class="chapter-item expanded "><a href="unsafe-blocks.html"><strong aria-hidden="true">15.2.</strong> 非安全代码块</a></li><li class="chapter-item expanded "><a href="behavior-considered-undefined.html"><strong aria-hidden="true">15.3.</strong> 未定义行为</a></li><li class="chapter-item expanded "><a href="behavior-not-considered-unsafe.html"><strong aria-hidden="true">15.4.</strong> 不被认为是非安全的行为</a></li></ol></li><li class="chapter-item expanded "><a href="const_eval.html"><strong aria-hidden="true">16.</strong> 常量求值</a></li><li class="chapter-item expanded "><a href="abi.html"><strong aria-hidden="true">17.</strong> ABI</a></li><li class="chapter-item expanded "><a href="runtime.html"><strong aria-hidden="true">18.</strong> Rust运行时</a></li><li class="chapter-item expanded "><a href="appendices.html"><strong aria-hidden="true">19.</strong> 附录</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macro-ambiguity.html"><strong aria-hidden="true">19.1.</strong> 宏定义规范</a></li><li class="chapter-item expanded "><a href="influences.html"><strong aria-hidden="true">19.2.</strong> 影响来源</a></li><li class="chapter-item expanded "><a href="glossary.html"><strong aria-hidden="true">19.3.</strong> 术语表</a></li><li class="chapter-item expanded "><a href="本书术语翻译对照表.html"><strong aria-hidden="true">19.4.</strong> 本书术语翻译对照表</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title"></h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        
                        <a href="https://gitee.com/minstrel1977/rust-reference" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>
                        
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <blockquote>
<p>本书跟随原文截止日期：2021-07-24</p>
</blockquote>
<h1><a class="header" href="#前言" id="前言">前言</a></h1>
<h2><a class="header" href="#试水版" id="试水版">试水版</a></h2>
<p>本译作是译者自己在学习 Rust 时，有感于国内 Rust 中文学习资源贫乏的激情之作。</p>
<p>译者在阅读和练习完了 Rust 的入门经典 <a href="https://doc.rust-lang.org/book/">The Rust Programming Language</a> 和 <a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust by Example</a> 之后，发现自己对 Rust 非常感兴趣，就一发不可收拾地继续投入精力来深入学习。在这个继续学习的过程中译者发现自己在不断的翻阅官网的 <a href="https://doc.rust-lang.org/stable/reference/">参考手册(Reference)</a>。</p>
<p>直接查看英语原文的确对理解 Rust 的基础概念很有帮助，但毕竟看英文效率太低；并且原文作为专业的工具书在读者设定上对阅读者做了较高的基础知识储备和 Rust 领域知识的假设；以及由于原文并未正式完工，还在不断增补中，所以其为追求效率导致其使用的英语语法比较简略随意，对基础知识和背景知识的省略严重，导致对译者这样的非英语母语者阅读起来体验并不好。所以译者就萌生了自己对阅读理解做翻译笔记的想法。</p>
<p>在做翻译笔记的时候发现很多技术坎要过，需要核对一下自己的理解到底对不对，就想偷懒看看中文网内有没有业内大佬把这些资源翻译为中文的，或者这本书的直接翻译版。很遗憾，Rust 在国内不怎么流行，中文资源不多，又很零碎分散，所以很长一段时间之内，译者并没有发现，后来通过 <a href="https://rustcc.cn/">Rust语言中文社区</a>发现国内站点-<a href="https://books.budshome.com">芽之家</a>上有<a href="https://books.budshome.com/rust-reference/">Rust Reference</a>的翻译版。小激动了一番之后发现此版本的翻译者在翻译完前几章后中途弃坑了。</p>
<p>此发现虽有遗憾，但也激发了译者的勇气，既然有人敢开头，那我就敢给他接力翻译几篇。但遗憾的是译者发现<a href="https://books.budshome.com">芽之家</a>的译本对译者来说仍不是很好理解，也不能及时的和 Rust 官网上的 <a href="https://doc.rust-lang.org/stable/reference/">参考手册(Reference)</a>保持同步。所以译者就依仗着有道翻译决定单干，所以本书的前期的格式和部分名词的译法参照了此版本。所以译者在此特别感谢此版本的翻译者给译者的勇气。</p>
<p>因为译者本身非计算机专科出身，又只是 Rust 的入门学习者，又是首次尝试这么大的翻译量，所以书中难免有不少翻译错误或者译者理解错误的地方，但译者的对 Rust 的热爱还在，对 Rust 学习的热情还在，所以就直接厚着脸皮拿出来献丑。译者这样做一是致敬 Rust，一是希望为国内 Rust 社区的繁荣尽些热心，更是为了提高译者自己的学习水平。当然也希望能激发更多学习者的热情；同时也希望读者能帮助译者进步，不止于帮助译者改进本书。</p>
<p>最后，因为译者实在是水平有限，对本书附录的 <a href="macro-ambiguity.html">Macro Follow-Set Ambiguity Formal Specification</a> 实在是无能为力了，只能翻译一半停下，希望读者中的高手能帮忙继续翻译，或者直接重新翻译，或者给译者指点一下也行。</p>
<h2><a class="header" href="#抢救版" id="抢救版">抢救版</a></h2>
<p>由于自己的才疏学浅，本译作发布之后，发现了不少翻译错误和译者对 Rust 知识点的理解错误，所以译者不得不再次鼓起勇气来检查和改正这些错误和失误。经过半个月的时间紧急抢救，现在译者终于有信心再次宣布——本译作救活了，可以一看了！</p>
<h2><a class="header" href="#翻译说明" id="翻译说明">翻译说明</a></h2>
<h3><a class="header" href="#翻译风格" id="翻译风格">翻译风格</a></h3>
<p>本书基本是忠于原文的直译，但针对比较晦涩的地方，本书采用了译者自己的理解的意译。但译者本身也是 Rust 的一个入门学习者，所以这里难免出错，所以这里恳请读者及时指正，以免译者贻害其他读者。</p>
<p>也因为大部分是直译，所以行文并不是很符合中文的阅读习惯，比如同一句话里的定语过多，比如前后两句话没有明显的承接关系等。开始时译者也想把这些修改为符合中文阅读的行文方式，但一是发现工作量有些大，再则，也是主要的，就是在修改的过程中难免加入译者过多的演绎，这样很可能偏离原作的语义，所以暂时没改。其实根据后来译者的检查阅读体验发现，这样的行文反倒是有助于提高阅读时的专注力，比如，停下来对一句话里“...的...的”划分反倒是能让读者更深入理解语义。所以译者愿意相信这百分之十几的阅读磕顿有助于提升这作为一部工具书的价值。</p>
<p>有时针对同一个英文原文，社区可能存在多种流行度差不多译法或译者认为自己的译法更贴切时，译者会采用格式“A译法/B译法”来同时给出这两种译法，比如，grammar 就翻译为“文法/语法”。</p>
<p>一个问题是译者对原文章节段落标题的翻译。这样做是原文的文档链接仍然有效，这样能有效降低译者对文档链接的维护，也能降低译者对一些名词的专门维护，还能有效提醒读者本章节段落的主题。</p>
<p>再一个问题是译文中的“译者注”，这里原本是译者加入的自我理解，以便降低新手的阅读门槛。但后来发现有些泛滥，并且译者的过分演绎发挥可能影响阅读体验，甚至曲解原意，所以译者删除了一部分，后续翻译也尽量克制了这一冲动。</p>
<p>再有就是对一些名词的翻译，译者基本上是遵循了 <a href="https://learnku.com/">LearnKu</a> 上的 <a href="https://learnku.com/articles/43623">Rust 语言术语中英文对照表</a>上的约定，但也有一些译者按自己的理解做了新的翻译，这些<a href="%E7%BF%BB%E8%AF%91%E8%AF%B4%E6%98%8E.html#%E7%BA%A6%E5%AE%9A">下节</a>和本书最后的<a href="%E6%9C%AC%E4%B9%A6%E6%9C%AF%E8%AF%AD%E7%BF%BB%E8%AF%91%E5%AF%B9%E7%85%A7%E8%A1%A8.html">本书术语翻译对照表</a>中说明。</p>
<p>Rust 的每种句法都有自己独特的句法规则，前期译者对这部分内容做了翻译，但发现翻译后无法保持句法规则的清晰性，严重妨碍读者对其的理解，尤其是其中的 <a href="tokens.html">token</a> 和[产生式(production)]如果翻译了就完全丢失了其中蕴含的格式意义，所以这部分译者就放弃了，直接拷贝了原文。</p>
<p>译者最近开始学习编译原理，发现本书的有不少译法跟标准的译法还是有差异，但译者最近有些精力不济了，所以译者准备等编译原理学完之后再统一改，所以再次对各位读者先说声抱歉，也欢迎各位读者提交 PR 先行修改。 </p>
<blockquote>
<p>待续</p>
</blockquote>
<h3><a class="header" href="#约定" id="约定">约定</a></h3>
<p>如果一些词译者觉得只使用中文行文可能会导致读者迷惑，那译者就会使用半角的圆括号把原英文带出，比如：标称类型(nominal type)。<br />
但有一类虽然比较浅显，译者还是采用了这种格式，比如：结构体(<code>struct</code>)，这类是其实是原文直接使用了 Rust 文法中的简单<a href="tokens.html">token</a> 来指代相关名词的方便做法。这类做法的另一个含义是这这类词代表了某种特定和关键的意义，并有可能直接出现源码中。所以译者的这种翻译方法也是为了不遗失这部分含义。<br />
还有一类是针对比较生僻或非常专业的原文，译者可能较多的采用了意译，比如 “Macro Kleene Matcher”，可能译为“宏克林闭包匹配器”比较专业，但译者意译为“可匹配空的宏匹配器”，专业性是降低了，但也可能照顾了部分非专业读者。</p>
<p>译文中还有许多全角圆括号，这些有可能是原文行文中就有的括号，也可能是译者为中文行文方便添加进来的，也有是译者为补充语义、方便阅读特意添加进来的（这部分主要是译者注太多了，译者看着也烦）。</p>
<p>再有就是翻译难免加上译者的理解，尤其是译者有强烈的愿望希望在不降低此书作为手册之外，能尽可能的降低此书的阅读门槛，所以译者除了多处采用意译、补充原文省略词外，还采用了了在部分晦涩或译者认为需要提醒的地方采用了右上角标注跳转链接的方式，这里跳转处的解释很多都是译者自己的理解，特提请读者注意辨别。</p>
<p>一些不确定该如何翻译的名词，译者也遵循一般原则没有强翻。但如果一个专有名词又有中文又有英文，译者就有意没在这两个次词/字中间留有空格，例如：“trait对象”。尤其是那些原文带有 token 含义的名词，译者也一般把它们“紧密结合”在一起，比如：<code>let</code>语句、<code>cfg</code>属性等。</p>
<p>每章节译文开头，译者都把其对应的原文链接地址和本译文对应的 commit id 给放上了。同时也把译者最后维护的时间给放上。这些是希望将来的其他贡献者能共同遵守。<br />
本翻译说明的开头还附上了本书最后一次维护时同步原文的时间。</p>
<blockquote>
<p>待续</p>
</blockquote>
<h4><a class="header" href="#常用词翻译" id="常用词翻译">常用词翻译</a></h4>
<ol>
<li>lifetime，社区一般译为“生命周期”，但在本书原文中有行文用到 lifecycle，本译作为何此词译义分开，选择翻译为“生存期”。并且译者在翻译中发现使用“生存期”在中文中行文更合适。</li>
<li>Syntax，这个词很多译者的随意的翻译为“语法”，但在本书里它大部分时候特指单一语言部件的产生式格式，所以本书统一翻译为“句法”。在它之上一层的语言组织方式才翻译为“文法”，有时也翻译为“语法”。</li>
<li>nominal type：标称类型。这是译者自创的一个翻译方法，首先 nominal type 在目前国内 Rust 社区里还没有合适的翻译先例，所以译者这里就蹭机器学习的热点翻译为“标称类型”，这种行径虽然降低了Rust的逼格，但在目前状态下，收益可能还是值得的。</li>
<li>item，这个一般翻译为“项”或“条目”，译者期初为了读起来更符合习惯，选择了“项”的翻译方法，但后来发现这个方法太容易引起歧义，无法体现出其作为语法单元的特殊含义，所以又给它添了两个字，变成了“程序项”。发布后，听从网友“<a href="https://www.zhihu.com/people/yan-han-bing-74">无聊</a>”的建议，又统一改为“程序项”。而其他名词复合时，一般会简化翻译为“XX项”，如：“static item”，译者就翻译为“静态项”。</li>
<li>size，社区内常把这个词在表示 Rust 数据类型的位宽时译做“大小”，但在中文语境中，有时无法把其和数值大小，以及比较意义的大小，或长度等含义快速区分开来，所以本文在表示 Rust 数据类型的位宽时统一译做“尺寸”。</li>
<li>bit，这个通常译为“位”，但有时它会和中文中的“两位数”的“位”混淆，所以在代表二进制位宽时译者干脆保持不译。</li>
<li>alignment，这个词在表示一种布局属性时，通常译作“对齐”，但本书由于体量较大，行文中很难把其和动词的“对齐”，以及普通意义上的“对齐”区分开来，所以在特指布局属性中的 alignment 时，统一翻译为“对齐量”。出于同样的考虑，representation 在表示类型的布局属性时统一翻译为“表形”。</li>
<li>更多常用词汇的翻译对照见<a href="%E6%9C%AC%E4%B9%A6%E6%9C%AF%E8%AF%AD%E7%BF%BB%E8%AF%91%E5%AF%B9%E7%85%A7%E8%A1%A8.html">本书术语翻译对照表</a>。</li>
</ol>
<h2><a class="header" href="#阅读建议" id="阅读建议">阅读建议</a></h2>
<p>本译作的英文原文主语省略很严重，但基本规律是省略的主语大部分是本节的标题，所以译者也很多时候继承了这个风格，所以阅读某一具体章节的时候，请读者主动把语义范围缩小为当前讲述的话题点上。</p>
<blockquote>
<p><strong>建议</strong>：译者希望本书的读者中，那些有一定水平或有能力直接进行英文阅读的读者还是要读一读阅读英文原文，顺便也请这部分读者在对比阅读的同时本书提高翻译质量。</p>
</blockquote>
<blockquote>
<p>待续</p>
</blockquote>
<h2><a class="header" href="#贡献力量" id="贡献力量">贡献力量</a></h2>
<p>译者欢迎各种形式的贡献和指导。</p>
<blockquote>
<p>待续</p>
</blockquote>
<h2><a class="header" href="#版权说明" id="版权说明">版权说明</a></h2>
<p>Nightly 版本放在国内 Gitee 上，采用 <a href="https://gitee.com/minstrel1977/rust-reference/blob/master/LICENSE">MulanPSL-2.0</a>；stable 版放在 github 上，采用 MIT。</p>
<!-- 2021-1-5-->
<!-- checked --><h1><a class="header" href="#introduction" id="introduction">Introduction</a></h1>
<h1><a class="header" href="#介绍" id="介绍">介绍</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/introduction.md">introduction.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<p>本书是 Rust 编程语言的主要参考手册，本书提供了3类资料：</p>
<ul>
<li>一些章节非正式地介绍了该语言的各种语言结构及其用法。</li>
<li>一些章节非正式地介绍了该语言的内存模型、并发模型、运行时服务、链接模型，以及调试工具。-</li>
<li>附录章节提供了一些对 Rust 语言有影响的编程原理和参考资料。</li>
</ul>
<div class="warning">
<p>警告：此书尚未完成，记录 Rust 的所有内容需要花些时间。有关本书未记录的内容，请查阅 <a href="https://github.com/rust-lang/reference/issues">GitHub issues</a>。</p>
</div>
<h2><a class="header" href="#rust-releases" id="rust-releases">Rust releases</a></h2>
<h2><a class="header" href="#rust-发行版" id="rust-发行版">Rust 发行版</a></h2>
<p>Rust 每六周发布一种新的版本。
该语言的第一个稳定版本是 Rust 1.0.0，然后是 Rust 1.1.0，以此类推。
相应的工具（<code>rustc</code>、’<code>cargo</code>，等）和文档(<a href="https://doc.rust-lang.org/std/index.html">标准库</a>、本书，等等)与语言版本一起发布。</p>
<p>本书的最新版本，与最新的 Rust 版本相匹配，它总是在 <a href="https://doc.rust-lang.org/reference/">https://doc.rust-lang.org/reference/</a> 等你。</p>
<p>通过在此链接的“reference”路径段之前添加相应的 Rust版本号，可以找到以往的版本。
比如，Rust 1.49.0版在 <a href="https://doc.rust-lang.org/1.49.0/reference/">https://doc.rust-lang.org/1.49.0/reference/</a> 下。</p>
<h2><a class="header" href="#what-the-reference-is-not" id="what-the-reference-is-not">What <em>The Reference</em> is Not</a></h2>
<h2><a class="header" href="#参考手册-并非" id="参考手册-并非"><em>参考手册</em> 并非——</a></h2>
<p>这本书不是对这门语言的入门介绍。本书假设您熟悉该语言。若您需要学习该语言的基础知识，请阅读 <a href="https://doc.rust-lang.org/book/index.html">Rust程序设计语言</a>。</p>
<p>这本书也不作为 Rust 语言发行版中包含的<a href="https://doc.rust-lang.org/std/index.html">标准库</a>的参考资料。Rust 的库文档是从其源代码文件中提取的文档属性。此外，有许多可能被可能认为是语言自带特性(features)的特性其实都是 Rust 的标准库的特性，所以您要寻找的特性可能在那里，而不是在这里。</p>
<p>类似地，本书通常不能作为记录 rustc 或者 Cargo 细节的工具书。rustc 有自己专门的书 <a href="https://doc.rust-lang.org/rustc/index.html">rustc book</a>，Cargo 也有一本书 <a href="https://doc.rust-lang.org/cargo/index.html">cargo book</a>，该书中包含了 Cargo 的[参考手册] <a href="https://doc.rust-lang.org/cargo/reference/index.html">cargo reference</a>。本书也涉及了少量和它们的相关知识，比如<a href="linkage.html">链接</a>的章节，介绍了 rustc 是如何工作的。</p>
<p>本书仅作为稳定版 Rust 的参考资料存在，关于尚在开发中的非稳定特性，请参阅 <a href="https://doc.rust-lang.org/nightly/unstable-book/">Unstable Book</a>。</p>
<p>Rust编译器（包括 <code>rustc</code>）将执行编译优化，但本参考手册不指导这些编译器的优化工作，所以只能把编译后的程序看作一个黑盒子。如果想侦测它的优化方式，只能通过运行它、给它提供输入并观察它的输出来推断。所有的编译器优化结果和程序的运行效果都必须和本参考手册所说的保持一致。</p>
<p>最后，本书并非 Rust 语言规范。它可能包含特定于 <code>rustc</code> 的细节，这不应该被当作 Rust 语言的规范。我们打算以后出版这样一本书，但在那之前，本手册是最接近的东西。</p>
<h2><a class="header" href="#how-to-use-this-book" id="how-to-use-this-book">How to Use This Book</a></h2>
<h2><a class="header" href="#如何使用此书" id="如何使用此书">如何使用此书</a></h2>
<p>本书不会假定您是按顺序阅读本书。本书的每一章一般都可以独立阅读，但会交叉链接到其他章节，以了解它们所相关的内容，但不会进行讨论。</p>
<p>阅读本书有两种主要方式。</p>
<p>第一是寻找特定问题的答案。如果您知道回答问题的章节，您可以直接从目录跳入该章节进行阅读。否则，您可以按 <code>s</code> 键或单击顶部栏上的放大镜来搜索与问题相关的关键字（译者注：目前本翻译版还不支持这种搜索功能）。例如，假设您想知道在 <code>let</code>语句中创建的临时值何时被销毁；同时，假设您还不知道<a href="expressions.html">表达式</a>那一章中定义了<a href="expressions.html#temporaries">临时对象的生存期</a>，那么可以搜索 “temporary let” ，第一个搜索结果将带您去阅读该部分。</p>
<p>第二是提高您对此语言某一方面的认知。在这种情况下，只需浏览目录，直到看到您想了解的内容，然后点开阅读。阅读中如果某个链接看起来很有帮助，那就点击并阅读该部分内容。</p>
<p>也就是说，本书没有错误的阅读方式。您觉得怎样读对您最有帮助就怎样读。</p>
<h3><a class="header" href="#conventions" id="conventions">Conventions</a></h3>
<h3><a class="header" href="#约定-1" id="约定-1">约定</a></h3>
<p>像所有技术书籍一样，在如何展示信息方面，本书有一些约定。这些约定记录如下。</p>
<ul>
<li>
<p>定义术语的语句中，术语写为<em>斜体</em>。当术语在其定义章节之外使用时，通常会有一个链接来指向该术语定义的章节。</p>
<p><em>示例术语</em> 这是一个定义术语的示例。</p>
</li>
<li>
<p>编译 crate 所使用的版本之间的语言差异用一个块引用表示，以<strong>粗体</strong>的“版本差异：”开头。</p>
<blockquote>
<p><strong>版本差异</strong>：此句法(syntax)在 2015 版本有效，2018 版本起不允许使用。</p>
</blockquote>
</li>
<li>
<p>一些有用信息，比如有关本书状态，或指出有用但大多超出本书范围的信息，大都位于以<strong>粗体</strong>的“注：”开头的块注释中。</p>
<blockquote>
<p><strong>注</strong>：这是一个注释示例。</p>
</blockquote>
</li>
<li>
<p>有关对语言的不健全(sound)行为，或者针对易于混淆的语言特性的警告，记录在特殊的警告框里。</p>
<div class="warning">
<p>警告：这是一个示例警告。</p>
</div>
</li>
<li>
<p>文本中内联的代码片段在 <code>&lt;code&gt;</code> 标签里。</p>
<p>较长的代码示例放在突出显示句法(syntax)的框中，该框的右上角有用于复制、执行和显示隐藏行的控件</p>
<pre><pre class="playground"><code class="language-rust edition2018"><span class="boring">// 这是隐藏行。
</span>fn main() {
    println!(&quot;这是一段示例代码。&quot;);
}
</code></pre></pre>
<p>除非另有说明，否则所有示例均使用最新版本的语法和编译检查。</p>
</li>
<li>
<p>文法和词法结构放在块引用中，第一行为粗体上标的 <sup><strong>词法</strong></sup> 或 <sup><strong>句法</strong></sup>。</p>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ExampleGrammar</em>:<br />
      <code>~</code> <a href="expressions.html"><em>Expression</em></a><br />
   | <code>box</code> <a href="expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>查阅<a href="notation.html">表义符(notation)</a>以获取更多细节。</p>
</li>
</ul>
<h2><a class="header" href="#contributing" id="contributing">Contributing</a></h2>
<h2><a class="header" href="#贡献力量-1" id="贡献力量-1">贡献力量</a></h2>
<p>我们欢迎各种形式的贡献。</p>
<p>您可以通过开启议题或向 <a href="https://github.com/rust-lang/reference/">Rust 参考手册仓库</a>发送 PR 来为本书做出贡献。如果这本书没有回答您的问题，并且您认为它的答案应该在本书的范围内，请不要犹豫，<a href="https://github.com/rust-lang/reference/issues">提交议题</a>或在 <a href="https://rust-lang.zulipchat.com/#narrow/stream/237824-t-lang.2Fdoc">Zulip</a> 的 <code>t-lang/doc</code> 流频道上询问。知道人们最喜欢用这本书来做什么将有助于引导我们的注意力来让这些部分变得更好。我们也希望此手册尽可能地规范，所以如果你看到任何错误或非规范的地方，但没有明确指出，也请[提交议题]。</p>
<h1><a class="header" href="#notation" id="notation">Notation</a></h1>
<h1><a class="header" href="#表义符符号" id="表义符符号">表义符/符号</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/notation.md">notation.md</a><br />
commit: dd1b9c331eb14ea7047ed6f2b12aaadab51b41d6 <br />
本章译文最后维护日期：2020-11-7</p>
</blockquote>
<h2><a class="header" href="#grammar" id="grammar">Grammar</a></h2>
<h2><a class="header" href="#文法语法" id="文法语法">文法/语法</a></h2>
<p>下表中的各种表义符会在本书中标有 <em>词法</em> 和 <em>句法</em> 的文法片段中用到：</p>
<table><thead><tr><th>表义符</th><th>示例</th><th>释义</th></tr></thead><tbody>
<tr><td>CAPITAL</td><td>KW_IF, INTEGER_LITERAL</td><td>由词法分析生成的单一 token</td></tr>
<tr><td><em>ItalicCamelCase</em></td><td><em>LetStatement</em>, <em>Item</em></td><td>句法产生式(syntactical production)</td></tr>
<tr><td><code>string</code></td><td><code>x</code>, <code>while</code>, <code>*</code></td><td>确切的字面字符(串)</td></tr>
<tr><td>\x</td><td>\n, \r, \t, \0</td><td>转义字符</td></tr>
<tr><td>x<sup>?</sup></td><td><code>pub</code><sup>?</sup></td><td>可选项</td></tr>
<tr><td>x<sup>*</sup></td><td><em>OuterAttribute</em><sup>*</sup></td><td>x 重复零次或多次</td></tr>
<tr><td>x<sup>+</sup></td><td><em>MacroMatch</em><sup>+</sup></td><td>x 重复一次或多次</td></tr>
<tr><td>x<sup>a..b</sup></td><td>HEX_DIGIT<sup>1..6</sup></td><td>x 重复 a 到 b 次</td></tr>
<tr><td>|</td><td><code>u8</code> | <code>u16</code>, Block | Item</td><td>或</td></tr>
<tr><td>[ ]</td><td>[<code>b</code> <code>B</code>]</td><td>列举的任意字符</td></tr>
<tr><td>[ - ]</td><td>[<code>a</code>-<code>z</code>]</td><td>a 到 z 范围内的任意字符(包括 a 和 z)</td></tr>
<tr><td>~[ ]</td><td>~[<code>b</code> <code>B</code>]</td><td>列举范围外的任意字符(序列)</td></tr>
<tr><td>~<code>string</code></td><td>~<code>\n</code>, ~<code>*/</code></td><td>此字符序列外的任意字符(序列)</td></tr>
<tr><td>( )</td><td>(<code>,</code> <em>Parameter</em>)<sup>?</sup></td><td>程序项分组</td></tr>
</tbody></table>
<h2><a class="header" href="#string-table-productions" id="string-table-productions">String table productions</a></h2>
<h2><a class="header" href="#字符串表产生式" id="字符串表产生式">字符串表产生式</a></h2>
<p>文法中的一些规则 — 比如<a href="expressions/operator-expr.html#borrow-operators">一元运算符</a>，<a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">二元运算符</a>和<a href="keywords.html">关键字</a> — 会以简化形式：作为可打印字符串的列表形式（在本书的相关章节的头部的各种产生式定义/句法规则里）给出。这些规则构成了关于 <a href="tokens.html">token</a>规则的规则子集，并且它们被假定为源码编译时的词法分析阶段的结果被再次输入给解析器，然后由一个<abbr title="确定性有限自动机(Deterministic Finite Automaton)">DFA</abbr>驱动，对此字符串表里的所有条目(string table entries)进行析取(disjunction)操作（来进行句法分析）。</p>
<p>本书还约定，当文法表中出现如 <code>monospace</code> 这样的字符串时，它代表对这些产生式中的单一 token 成员的隐式引用。查阅 <a href="tokens.html">tokens</a> 以获取更多信息。</p>
<!-- 2020-11-12-->
<!-- checked --><h1><a class="header" href="#词法结构" id="词法结构">词法结构</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/lexical-structure.md">notation.md</a><br />
commit: 4a2bdf896cd2df370a91d14cb8ba04e326cd21db <br />
本章译文最后维护日期：2020-10-17</p>
</blockquote>
<!-- 2020-11-12-->
<!-- checked --><h1><a class="header" href="#输入格式" id="输入格式">输入格式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/input-format.md">notation.md</a><br />
commit: a2405b970b7c8222a483b82213adcb17d646c75d <br />
本章译文最后维护日期：2020-11-5</p>
</blockquote>
<p>Rust 输入被解释为用 UTF-8 编码的 Unicode 字符序列。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#keywords" id="keywords">Keywords</a></h1>
<h1><a class="header" href="#关键字" id="关键字">关键字</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/keywords.md">keywords.md</a><br />
commit: 6eb3e87af2c7743d6c7c783154cc380c4b0ea270
本章译文最后维护日期：2021-04-23</p>
</blockquote>
<p>Rust 将关键字分为三类：</p>
<ul>
<li><a href="keywords.html#strict-keywords">严格关键字</a></li>
<li><a href="keywords.html#reserved-keywords">保留关键字</a></li>
<li><a href="keywords.html#weak-keywords">弱关键字</a></li>
</ul>
<h2><a class="header" href="#strict-keywords" id="strict-keywords">Strict keywords</a></h2>
<h2><a class="header" href="#严格关键字" id="严格关键字">严格关键字</a></h2>
<p>这类关键字只能在正确的上下文中使用。它们不能用作以下名称：</p>
<ul>
<li><a href="items.html">程序项(item)</a></li>
<li><a href="variables.html">变量</a>和函数参数</li>
<li>字段(field)和<a href="items/enumerations.html">变体</a></li>
<li><a href="types/parameters.html">类型参数</a></li>
<li>生存期参数或者<a href="expressions/loop-expr.html#loop-labels">循环标签</a></li>
<li><a href="macros.html">宏</a>或<a href="attributes.html">属性</a></li>
<li><a href="macros-by-example.html">宏占位符</a></li>
<li><a href="crates-and-source-files.html">crate</a></li>
</ul>
<blockquote>
<p><strong><sup>词法分析:<sup></strong><br />
KW_AS             : <code>as</code><br />
KW_BREAK          : <code>break</code><br />
KW_CONST          : <code>const</code><br />
KW_CONTINUE       : <code>continue</code><br />
KW_CRATE          : <code>crate</code><br />
KW_ELSE           : <code>else</code><br />
KW_ENUM           : <code>enum</code><br />
KW_EXTERN         : <code>extern</code><br />
KW_FALSE          : <code>false</code><br />
KW_FN             : <code>fn</code><br />
KW_FOR            : <code>for</code><br />
KW_IF             : <code>if</code><br />
KW_IMPL           : <code>impl</code><br />
KW_IN             : <code>in</code><br />
KW_LET            : <code>let</code><br />
KW_LOOP           : <code>loop</code><br />
KW_MATCH          : <code>match</code><br />
KW_MOD            : <code>mod</code><br />
KW_MOVE           : <code>move</code><br />
KW_MUT            : <code>mut</code><br />
KW_PUB            : <code>pub</code><br />
KW_REF            : <code>ref</code><br />
KW_RETURN         : <code>return</code><br />
KW_SELFVALUE      : <code>self</code><br />
KW_SELFTYPE       : <code>Self</code><br />
KW_STATIC         : <code>static</code><br />
KW_STRUCT         : <code>struct</code><br />
KW_SUPER          : <code>super</code><br />
KW_TRAIT          : <code>trait</code><br />
KW_TRUE           : <code>true</code><br />
KW_TYPE           : <code>type</code><br />
KW_UNSAFE         : <code>unsafe</code><br />
KW_USE            : <code>use</code><br />
KW_WHERE          : <code>where</code><br />
KW_WHILE          : <code>while</code></p>
</blockquote>
<p>以下关键字从 2018 版开始启用。</p>
<blockquote>
<p><strong><sup>词法分析 2018+</sup></strong><br />
KW_ASYNC          : <code>async</code><br />
KW_AWAIT          : <code>await</code><br />
KW_DYN            : <code>dyn</code></p>
</blockquote>
<h2><a class="header" href="#reserved-keywords" id="reserved-keywords">Reserved keywords</a></h2>
<h2><a class="header" href="#保留关键字" id="保留关键字">保留关键字</a></h2>
<p>这类关键字目前还没有被使用，但是它们被保留以备将来使用。它们具有与严格关键字相同的限制。这样做的原因是通过禁止当前程序使用这些关键字，从而使当前程序能兼容 Rust 的未来版本。</p>
<blockquote>
<p><strong><sup>词法分析</sup></strong><br />
KW_ABSTRACT       : <code>abstract</code><br />
KW_BECOME         : <code>become</code><br />
KW_BOX            : <code>box</code><br />
KW_DO             : <code>do</code><br />
KW_FINAL          : <code>final</code><br />
KW_MACRO          : <code>macro</code><br />
KW_OVERRIDE       : <code>override</code><br />
KW_PRIV           : <code>priv</code><br />
KW_TYPEOF         : <code>typeof</code><br />
KW_UNSIZED        : <code>unsized</code><br />
KW_VIRTUAL        : <code>virtual</code><br />
KW_YIELD          : <code>yield</code></p>
</blockquote>
<p>以下关键字从 2018 版开始成为保留关键字。</p>
<blockquote>
<p><strong><sup>词法分析 2018+</sup></strong><br />
KW_TRY   : <code>try</code></p>
</blockquote>
<h2><a class="header" href="#weak-keywords" id="weak-keywords">Weak keywords</a></h2>
<h2><a class="header" href="#弱关键字" id="弱关键字">弱关键字</a></h2>
<p>这类关键字只有在特定的上下文中才有特殊的意义。例如，可以声明名为 <code>union</code> 的变量或方法。</p>
<ul>
<li>
<p><code>macro_rules</code> 用于创建自定义<a href="macros.html">宏</a>。</p>
</li>
<li>
<p><code>union</code> 用于声明<a href="items/unions.html">联合体(<code>union</code>)</a>，它只有在联合体声明中使用时才是关键字。</p>
</li>
<li>
<p><code>'static</code> 用于静态生存期，不能用作通用<a href="items/generics.html">泛型生存期参数</a>和<a href="expressions/loop-expr.html#loop-labels">循环标签</a></p>
<pre><code class="language-compile_fail">// error[E0262]: invalid lifetime parameter name: `'static`
fn invalid_lifetime_parameter&lt;'static&gt;(s: &amp;'static str) -&gt; &amp;'static str { s }
</code></pre>
</li>
<li>
<p>在 2015 版本中，当 <a href="types/trait-object.html"><code>dyn</code></a> 用在非 <code>::</code> 开头的路径限定的类型前时，它是关键字。</p>
<p>从 2018 版开始，<code>dyn</code> 被提升为一个严格关键字。</p>
</li>
</ul>
<blockquote>
<p><strong><sup>词法分析</sup></strong><br />
KW_UNION          : <code>union</code><br />
KW_STATICLIFETIME : <code>'static</code></p>
<p><strong><sup>词法分析 2015</sup></strong><br />
KW_DYN            : <code>dyn</code></p>
</blockquote>
<h1><a class="header" href="#identifiers" id="identifiers">Identifiers</a></h1>
<h1><a class="header" href="#标识符" id="标识符">标识符</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/identifiers.md">identifiers.md</a><br />
commit: 91c95a18e6aa0f5f687bab55a43fa0290afb6f1c <br />
本章译文最后维护日期：2021-07-24</p>
</blockquote>
<blockquote>
<p><strong><sup>词法分析:<sup></strong><br />
IDENTIFIER_OR_KEYWORD :<br />
      XID_Start XID_Continue<sup>*</sup><br />
   | <code>_</code> XID_Continue<sup>+</sup></p>
<p>RAW_IDENTIFIER : <code>r#</code> IDENTIFIER_OR_KEYWORD <sub><em>排除 <code>crate</code>, <code>self</code>, <code>super</code>, <code>Self</code></em></sub></p>
<p>NON_KEYWORD_IDENTIFIER : IDENTIFIER_OR_KEYWORD <sub>*排除<a href="keywords.html#strict-keywords">严格关键字</a>和<a href="keywords.html#reserved-keywords">保留关键字</a> *</sub></p>
<p>IDENTIFIER :<br />
NON_KEYWORD_IDENTIFIER | RAW_IDENTIFIER</p>
</blockquote>
<!-- When updating the version, update the UAX links, too. -->
<p>标识符遵循 <a href="https://www.unicode.org/reports/tr31/tr31-33.html">Unicode标准附录31</a> 中针对 Unicode 13.0版的规范，后面所述内容在此版本中均有备述。
这里举一些标识符的示例：</p>
<ul>
<li><code>foo</code></li>
<li><code>_identifier</code></li>
<li><code>r#true</code></li>
<li><code>Москва</code></li>
<li><code>東京</code></li>
</ul>
<p>其中 UAX #31 中要求标识符使用的（产生式）参数如下：</p>
<ul>
<li>起始字符 := <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&amp;abb=on&amp;g=&amp;i="><code>XID_Start</code></a>，外加一个下划线 (U+005F)</li>
<li>后续字符 := <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&amp;abb=on&amp;g=&amp;i="><code>XID_Continue</code></a></li>
<li>中间字符 := 空</li>
</ul>
<blockquote>
<p><strong>注意</strong>: 以下划线开头的标识符通常用于表示有意不会被实际使用的标识符，且会使 <code>rustc</code> 中未被使用的警告静音。</p>
</blockquote>
<p>如果标识符没有下面<a href="identifiers.html#raw-identifiers">原生标识符</a>章节中描述的 <code>r#</code>前缀，那它不能是<a href="keywords.html#strict-keywords">严格关键字</a>或<a href="keywords.html#reserved-keywords">保留关键字</a>。</p>
<p>标识符中不允许使用零宽度非连接符（ZWNJ U+200C）和零宽度连接符（ZWJ U+200D）。</p>
<p>在下列情况下，标识符仅限于 <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Start%3A%5D&amp;abb=on&amp;g=&amp;i="><code>XID_Start</code></a> 和 <a href="http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AXID_Continue%3A%5D&amp;abb=on&amp;g=&amp;i="><code>XID_Continue</code></a> 的ASCII子集：</p>
<ul>
<li><a href="items/extern-crates.html"><code>extern crate</code></a>声明</li>
<li><a href="paths.html">路径</a>中引用的外部 crate名</li>
<li>从文件系统中载入的未被<a href="items/modules.html#the-path-attribute"><code>path</code>属性</a>限定的<a href="items/modules.html">模块</a>名</li>
<li>被 <a href="abi.html#the-no_mangle-attribute"><code>no_mangle</code></a>属性限定的程序项</li>
<li><a href="items/external-blocks.html">外部块</a>中的程序项名称</li>
</ul>
<h2><a class="header" href="#normalization" id="normalization">Normalization</a></h2>
<h2><a class="header" href="#标准化" id="标准化">标准化</a></h2>
<p>标识符使用<a href="https://www.unicode.org/reports/tr15/tr15-50.html">Unicode标准附录15</a>中定义的规范化形式C（NFC）进行规范化。如果两个标识符的 NFC形式相等，那么它们就是等价的。</p>
<p>[过程宏][proc macro]和<a href="macros-by-example.html">声明宏</a>在其输入中接受规范化的标识符。</p>
<h2><a class="header" href="#raw-identifiers" id="raw-identifiers">Raw identifiers</a></h2>
<h2><a class="header" href="#原生标识符" id="原生标识符">原生标识符</a></h2>
<p>除了有形式前缀 <code>r#</code> 修饰外，原生标识符与普通标识符类似。（注意形式前缀 <code>r#</code> 不包括在实际标识符中。）与普通标识符不同，原生标识符可以是除上面列出的 <code>RAW_IDENTIFIER</code> 之外的任何严格关键字或保留关键字。</p>
<h1><a class="header" href="#comments" id="comments">Comments</a></h1>
<h1><a class="header" href="#注释" id="注释">注释</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/comments.md">comments.md</a><br />
commit: 993393d362cae51584d580f86c4f38d43ae76efc <br />
本章译文最后维护日期：2020-10-17</p>
</blockquote>
<blockquote>
<p><strong><sup>词法分析</sup></strong><br />
LINE_COMMENT :(译者注：行注释)<br />
      <code>/*</code> (~[<code>*</code> <code>!</code>] | <code>**</code> | <em>BlockCommentOrDoc</em>)
   | <code>//</code></p>
<p>BLOCK_COMMENT :(译者注：块注释)<br />
      <code>/*</code> (~[<code>*</code> <code>!</code>] | <code>**</code> | <em>BlockCommentOrDoc</em>)
(<em>BlockCommentOrDoc</em> | ~<code>*/</code>)<sup>*</sup> <code>*/</code><br />
   | <code>/**/</code><br />
   | <code>/***/</code> </p>
<p>INNER_LINE_DOC :(译者注：内部行文档型注释)<br />
   <code>//!</code> ~[<code>\n</code> <em>IsolatedCR</em>]<sup>*</sup></p>
<p>INNER_BLOCK_DOC :(译者注：内部块文档型注释)<br />
   <code>/*!</code> ( <em>BlockCommentOrDoc</em> | ~[<code>*/</code> <em>IsolatedCR</em>] )<sup>*</sup> <code>*/</code></p>
<p>OUTER_LINE_DOC :(译者注：外部行文档型注释)<br />
   <code>///</code> (~<code>/</code> ~[<code>\n</code> <em>IsolatedCR</em>]<sup>*</sup>)<sup>?</sup></p>
<p>OUTER_BLOCK_DOC :(译者注：外部块文档型注释)<br />
   <code>/**</code> (~<code>*</code> | <em>BlockCommentOrDoc</em> )
(<em>BlockCommentOrDoc</em> | ~[<code>*/</code> <em>IsolatedCR</em>])<sup>*</sup> <code>*/</code></p>
<p><em>BlockCommentOrDoc</em> :(译者注：块注释或文档型注释)<br />
      BLOCK_COMMENT<br />
   | OUTER_BLOCK_DOC<br />
   | INNER_BLOCK_DOC</p>
<p><em>IsolatedCR</em> :<br />
   <em>后面没有跟 <code>\n</code> 的 <code>\r</code></em></p>
</blockquote>
<h2><a class="header" href="#non-doc-comments" id="non-doc-comments">Non-doc comments</a></h2>
<h2><a class="header" href="#非文档型注释" id="非文档型注释">非文档型注释</a></h2>
<p>Rust 代码中的注释一般遵循 C++ 风格的行（<code>//</code>）和块（<code>/* ... */</code>）注释形式，也支持嵌套的块注释。</p>
<p>非文档型注释(Non-doc comments)被解释为某种形式的空白符。</p>
<h2><a class="header" href="#doc-comments" id="doc-comments">Doc comments</a></h2>
<h2><a class="header" href="#文档型注释" id="文档型注释">文档型注释</a></h2>
<p>以<em>三个</em>斜线（<code>///</code>）开始的行文档型注释，以及块文档型注释（<code>/** ... */</code>），均为内部文档型注释。它们被当做 <a href="https://doc.rust-lang.org/rustdoc/the-doc-attribute.html"><code>doc</code>属性</a>的特殊句法解析。也就是说，它们等同于把注释内容写入 <code>#[doc=&quot;...&quot;]</code> 里。例如：<code>/// Foo</code> 等同于 <code>#[doc=&quot;Foo&quot;]</code>，<code>/** Bar */</code> 等同于 <code>#[doc=&quot;Bar&quot;]</code>。</p>
<p>以 <code>//!</code> 开始的行文档型注释，以及 <code>/*! ... */</code> 形式的块文档型注释属于注释体所在对象的文档型注释，而非注释体之后的程序项的。也就是说，它们等同于把注释内容写入 <code>#![doc=&quot;...&quot;]</code> 里。<code>//!</code> 注释通常用于标注模块位于的文件。</p>
<p>孤立的 CRs（<code>\r</code>），如果其后没有紧跟有 LF（<code>\n</code>），则不能出现在文档型注释中。</p>
<h2><a class="header" href="#示例" id="示例">示例</a></h2>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>//! 应用于此 crate 的隐式匿名模块的文档型注释

pub mod outer_module {

    //!  - 内部行文档型注释
    //!! - 仍是内部行文档型注释 (但是这样开头会更具强调性)

    /*!  - 内部块文档型注释 */
    /*!! - 仍是内部块文档型注释 (但是这样开头会更具强调性) */

    //   - 普通注释
    ///  - 外部行文档型注释 (以 3 个 `///` 开始)
    //// - 普通注释

    /*   - 普通注释 */
    /**  - 外部块文档型注释 (exactly) 2 asterisks */
    /*** - 普通注释 */

    pub mod inner_module {}

    pub mod nested_comments {
        /* 在 Rust 里 /* 我们可以 /* 嵌套注释 */ */ */

        // 所有这三种类型的块注释都可以包含或嵌套在任何其他类型的
        // 注释中：

        /*   /* */  /** */  /*! */  */
        /*!  /* */  /** */  /*! */  */
        /**  /* */  /** */  /*! */  */
        pub mod dummy_item {}
    }

    pub mod degenerate_cases {
        // 空内部行文档型注释
        //!

        // 空内部块文档型注释
        /*!*/

        // 空行注释
        //

        // 空外部行文档型注释
        ///

        // 空块注释
        /**/

        pub mod dummy_item {}

        // 空的两个星号的块注释不是一个文档块，它是一个块注释。
        /***/

    }

    /* 下面这个是不允许的，因为外部文档型注释需要一个
       接收该文档的程序项 */

    /// 我的程序项呢?
<span class="boring">  mod boo {}
</span>}
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#whitespace" id="whitespace">Whitespace</a></h1>
<h1><a class="header" href="#空白符" id="空白符">空白符</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/whitespace.md">whitespace.md</a><br />
commit: dd1b9c331eb14ea7047ed6f2b12aaadab51b41d6 <br />
本章译文最后维护日期：2020-11-5</p>
</blockquote>
<p>空白符是非空字符串，它里面只包含具有 <a href="https://www.unicode.org/reports/tr31/"><code>Pattern_White_Space</code></a> 属性的 Unicode 字符，即:</p>
<ul>
<li><code>U+0009</code> (水平制表符, <code>'\t'</code>)</li>
<li><code>U+000A</code> (换行符, <code>'\n'</code>)</li>
<li><code>U+000B</code> (垂直制表符)</li>
<li><code>U+000C</code> (分页符)</li>
<li><code>U+000D</code> (回车符, <code>'\r'</code>)</li>
<li><code>U+0020</code> (空格符, <code>' '</code>)</li>
<li><code>U+0085</code> (下一行标记符)</li>
<li><code>U+200E</code> (从左到右标记符)</li>
<li><code>U+200F</code> (从右到标左记符)</li>
<li><code>U+2028</code> (行分隔符)</li>
<li><code>U+2029</code> (段分隔符)</li>
</ul>
<p>Rust是一种“格式自由(free-form)”的语言，这意味着所有形式的空白符在文法中仅用于分隔 <em>tokens</em> 的作用，没有语义意义。</p>
<p>Rust 程序中，如果将一个空白符元素替换为任何其他合法的空白符元素（例如单个空格字符），它们仍有相同的意义。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#tokens" id="tokens">Tokens</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/tokens.md">tokens.md</a><br />
commit: 8e62ab3e5dc57f5db7581cf763bcbbea75ab58eb <br />
本章译文最后维护日期：2020-1-17</p>
</blockquote>
<p>token 是采用非递归方式的正则文法(regular languages)定义的基本语法产生式(primitive productions)。Rust 源码输入可以被分解成以下几类 token：</p>
<ul>
<li><a href="keywords.html">关键字</a></li>
<li><a href="identifiers.html">标识符</a></li>
<li><a href="tokens.html#literals">字面量</a></li>
<li><a href="tokens.html#lifetimes-and-loop-labels">生存期</a></li>
<li><a href="tokens.html#punctuation">标点符号</a></li>
<li><a href="tokens.html#delimiters">分隔符</a></li>
</ul>
<p>在本文档中，“简单”token 会直接在（相关章节头部的）[字符串表产生式(production)][string table production]表单中给出，并以 <code>monospace</code> 字体显示。（译者注：本译作的原文中，在文法表之外的行文中也会大量出现这种直接使用简单token 来替代相关名词的做法，一般此时如果译者觉得这种 token 需要翻译时，会使用诸如：结构体(<code>struct</code>) 这种形式来翻译。读者需要意识到“struct”是文法里的一个 token，能以其字面形式直接出现在源码里。）</p>
<h2><a class="header" href="#literals" id="literals">Literals</a></h2>
<h2><a class="header" href="#字面量" id="字面量">字面量</a></h2>
<p>字面量是一个由单一 token（而不是由一连串 tokens）组成的表达式，它立即、直接表示它所代表的值，而不是通过名称或其他一些求值/计算规则来引用它。字面量是<a href="const_eval.html#constant-expressions">常量表达式</a>的一种形式，所以它（主要）用在编译时求值。</p>
<h3><a class="header" href="#examples" id="examples">Examples</a></h3>
<h3><a class="header" href="#示例-1" id="示例-1">示例</a></h3>
<h4><a class="header" href="#characters-and-strings" id="characters-and-strings">Characters and strings</a></h4>
<h4><a class="header" href="#字符和字符串" id="字符和字符串">字符和字符串</a></h4>
<table><thead><tr><th></th><th>举例</th><th><code>#</code> 号的数量</th><th>字符集</th><th>转义</th></tr></thead><tbody>
<tr><td><a href="tokens.html#character-literals">字符</a></td><td><code>'H'</code></td><td>0</td><td>全部 Unicode</td><td><a href="tokens.html#quote-escapes">引号</a> &amp; <a href="tokens.html#ascii-escapes">ASCII</a> &amp; <a href="tokens.html#unicode-escapes">Unicode</a></td></tr>
<tr><td><a href="tokens.html#string-literals">字符串</a></td><td><code>&quot;hello&quot;</code></td><td>0</td><td>全部 Unicode</td><td><a href="tokens.html#quote-escapes">引号</a> &amp; <a href="tokens.html#ascii-escapes">ASCII</a> &amp; <a href="tokens.html#unicode-escapes">Unicode</a></td></tr>
<tr><td><a href="tokens.html#raw-string-literals">原生字符串</a></td><td><code>r#&quot;hello&quot;#</code></td><td>0 或更多*</td><td>全部 Unicode</td><td><code>N/A</code></td></tr>
<tr><td><a href="tokens.html#byte-literals">字节</a></td><td><code>b'H'</code></td><td>0</td><td>全部 ASCII</td><td><a href="tokens.html#quote-escapes">引号</a> &amp; <a href="tokens.html#byte-escapes">字节</a></td></tr>
<tr><td><a href="tokens.html#byte-string-literals">字节串</a></td><td><code>b&quot;hello&quot;</code></td><td>0</td><td>全部 ASCII</td><td><a href="tokens.html#quote-escapes">引号</a> &amp; <a href="tokens.html#byte-escapes">字节</a></td></tr>
<tr><td><a href="tokens.html#raw-byte-string-literals">原生字节串</a></td><td><code>br#&quot;hello&quot;#</code></td><td>0 或更多*</td><td>全部 ASCII</td><td><code>N/A</code></td></tr>
</tbody></table>
<p>* 字面量两侧的 <code>#</code> 数量必须相同。</p>
<h4><a class="header" href="#ascii-escapes" id="ascii-escapes">ASCII escapes</a></h4>
<h4><a class="header" href="#ascii-转义" id="ascii-转义">ASCII 转义</a></h4>
<table><thead><tr><th></th><th>名称</th></tr></thead><tbody>
<tr><td><code>\x41</code></td><td>7-bit 字符编码（2位数字，最大值为 <code>0x7F</code>）</td></tr>
<tr><td><code>\n</code></td><td>换行符</td></tr>
<tr><td><code>\r</code></td><td>回车符</td></tr>
<tr><td><code>\t</code></td><td>制表符</td></tr>
<tr><td><code>\\</code></td><td>反斜线</td></tr>
<tr><td><code>\0</code></td><td>Null</td></tr>
</tbody></table>
<h4><a class="header" href="#byte-escapes" id="byte-escapes">Byte escapes</a></h4>
<h4><a class="header" href="#字节转义" id="字节转义">字节转义</a></h4>
<table><thead><tr><th></th><th>名称</th></tr></thead><tbody>
<tr><td><code>\x7F</code></td><td>8-bit 字符编码（2位数字）</td></tr>
<tr><td><code>\n</code></td><td>换行符</td></tr>
<tr><td><code>\r</code></td><td>回车符</td></tr>
<tr><td><code>\t</code></td><td>制表符</td></tr>
<tr><td><code>\\</code></td><td>反斜线</td></tr>
<tr><td><code>\0</code></td><td>Null</td></tr>
</tbody></table>
<h4><a class="header" href="#unicode-escapes" id="unicode-escapes">Unicode escapes</a></h4>
<h4><a class="header" href="#unicode-转义" id="unicode-转义">unicode 转义</a></h4>
<table><thead><tr><th></th><th>名称</th></tr></thead><tbody>
<tr><td><code>\u{7FFF}</code></td><td>24-bit Unicode 字符编码（最多6个数字）</td></tr>
</tbody></table>
<h4><a class="header" href="#quote-escapes" id="quote-escapes">Quote escapes</a></h4>
<h4><a class="header" href="#引号转义" id="引号转义">引号转义</a></h4>
<table><thead><tr><th></th><th>Name</th></tr></thead><tbody>
<tr><td><code>\'</code></td><td>单引号</td></tr>
<tr><td><code>\&quot;</code></td><td>双引号</td></tr>
</tbody></table>
<h4><a class="header" href="#numbers" id="numbers">Numbers</a></h4>
<h4><a class="header" href="#数字" id="数字">数字</a></h4>
<table><thead><tr><th><a href="tokens.html#%E6%95%B0%E5%AD%97%E5%AD%97%E9%9D%A2%E9%87%8F">数字字面量</a><code>*</code></th><th>示例</th><th>指数</th><th>后缀</th></tr></thead><tbody>
<tr><td>十进制整数</td><td><code>98_222</code></td><td><code>N/A</code></td><td>整数后缀</td></tr>
<tr><td>十六进制整数</td><td><code>0xff</code></td><td><code>N/A</code></td><td>整数后缀</td></tr>
<tr><td>八进制整数</td><td><code>0o77</code></td><td><code>N/A</code></td><td>整数后缀</td></tr>
<tr><td>二进制整数</td><td><code>0b1111_0000</code></td><td><code>N/A</code></td><td>整数后缀</td></tr>
<tr><td>浮点数</td><td><code>123.0E+77</code></td><td><code>Optional</code></td><td>浮点数后缀</td></tr>
</tbody></table>
<p><code>*</code> 所有数字字面量允许使用 <code>_</code> 作为可视分隔符，比如：<code>1_234.0E+18f64</code></p>
<h4><a class="header" href="#suffixes" id="suffixes">Suffixes</a></h4>
<h4><a class="header" href="#后缀" id="后缀">后缀</a></h4>
<p>后缀是紧跟（无空白符）在字面量主体部分之后的非<a href="identifiers.html">原生标识符</a>(non-raw identifier)。</p>
<p>任何带有后缀的字面量（如字符串、整数等）都可以作为有效的 token，并且可以传递给宏而不会产生错误。宏自己决定如何解释这种 token，以及是否该报错。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! blackhole { ($tt:tt) =&gt; () }

blackhole!(&quot;string&quot;suffix); // OK
<span class="boring">}
</span></code></pre></pre>
<p>但是，最终被解析为 Rust 代码的字面量token 上的后缀是受限制的。对于非数字字面量token，任何后缀都最终将被弃用，而数字字面量token 只接受下表中的后缀。</p>
<table><thead><tr><th>整数</th><th>浮点数</th></tr></thead><tbody>
<tr><td><code>u8</code>, <code>i8</code>, <code>u16</code>, <code>i16</code>, <code>u32</code>, <code>i32</code>, <code>u64</code>, <code>i64</code>, <code>u128</code>, <code>i128</code>, <code>usize</code>, <code>isize</code></td><td><code>f32</code>, <code>f64</code></td></tr>
</tbody></table>
<h3><a class="header" href="#character-and-string-literals" id="character-and-string-literals">Character and string literals</a></h3>
<h3><a class="header" href="#字符和字符串字面量" id="字符和字符串字面量">字符和字符串字面量</a></h3>
<h4><a class="header" href="#character-literals" id="character-literals">Character literals</a></h4>
<h4><a class="header" href="#字符字面量" id="字符字面量">字符字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
CHAR_LITERAL :<br />
   <code>'</code> ( ~[<code>'</code> <code>\</code> \n \r \t] | QUOTE_ESCAPE | ASCII_ESCAPE | UNICODE_ESCAPE ) <code>'</code></p>
<p>QUOTE_ESCAPE :<br />
   <code>\'</code> | <code>\&quot;</code></p>
<p>ASCII_ESCAPE :<br />
      <code>\x</code> OCT_DIGIT HEX_DIGIT<br />
   | <code>\n</code> | <code>\r</code> | <code>\t</code> | <code>\\</code> | <code>\0</code></p>
<p>UNICODE_ESCAPE :<br />
   <code>\u{</code> ( HEX_DIGIT <code>_</code><sup>*</sup> )<sup>1..6</sup> <code>}</code></p>
</blockquote>
<p><em>字符字面量</em>是位于两个 <code>U+0027</code>（单引号 <code>'</code>）字符内的单个 Unicode 字符。当它是 <code>U+0027</code> 自身时，必须前置<em>转义</em>字符 <code>U+005C</code>（<code>\</code>）。</p>
<h4><a class="header" href="#string-literals" id="string-literals">String literals</a></h4>
<h4><a class="header" href="#字符串字面量" id="字符串字面量">字符串字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
STRING_LITERAL :<br />
   <code>&quot;</code> (<br />
      ~[<code>&quot;</code> <code>\</code> <em>IsolatedCR</em>]  (译者注：IsolatedCR：后面没有跟 <code>\n</code> 的 <code>\r</code>，首次定义见<a href="comments.html">注释</a>)<br />
      | QUOTE_ESCAPE<br />
      | ASCII_ESCAPE<br />
      | UNICODE_ESCAPE<br />
      | STRING_CONTINUE<br />
   )<sup>*</sup> <code>&quot;</code></p>
<p>STRING_CONTINUE :<br />
   <code>\</code> <em>后跟</em> \n</p>
</blockquote>
<p><em>字符串字面量</em>是位于两个 <code>U+0022</code> （双引号 <code>&quot;</code>）字符内的任意 Unicode 字符序列。当它是 <code>U+0022</code> 自身时，必须前置<em>转义</em>字符 <code>U+005C</code>（<code>\</code>）。</p>
<p>字符串字面量允许换行书写。换行可以用换行符（<code>U+000A</code>）表示，也可以用一对回车符换行符（<code>U+000D</code>, <code>U+000A</code>）的字节序列表示。这两种字节序列通常都会被转换为 <code>U+000A</code>，但有例外：当换行符前置一个未转义的字符 <code>U+005C</code>（<code>\</code>）时，会导致字符 <code>U+005C</code>、换行符和下一行开头的所有空白符都被忽略。因此下述示例中，<code>a</code> 和 <code>b</code> 是一样的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let a = &quot;foobar&quot;;
let b = &quot;foo\
         bar&quot;;

assert_eq!(a,b);
<span class="boring">}
</span></code></pre></pre>
<h4><a class="header" href="#character-escapes" id="character-escapes">Character escapes</a></h4>
<h4><a class="header" href="#字符转义" id="字符转义">字符转义</a></h4>
<p>不管是字符字面量，还是非原生字符串字面量，Rust 都为其提供了额外的<em>转义</em>功能。转义以一个 <code>U+005C</code>（<code>\</code>）开始，并后跟如下形式之一：</p>
<ul>
<li><em>7-bit 码点转义</em>以 <code>U+0078</code>（<code>x</code>）开头，后面紧跟两个<em>十六进制数字</em>，其最大值为 <code>0x7F</code>。它表示 ASCII 字符，其码值就等于字面提供的十六进制值。不允许使用更大的值，因为不能确定其是 Unicode 码点还是字节值(byte values)。</li>
<li><em>24-bit 码点转义</em>以 <code>U+0075</code>（<code>u</code>）开头，后跟多达六位<em>十六进制数字</em>，位于花括号 <code>U+007B</code>（<code>{</code>）和 <code>U+007D</code>（<code>}</code>）之间。这表示（需转义到的）Unicode 字符的码点等于花括号里的十六进制值。</li>
<li><em>空白符转义</em>是 <code>U+006E</code> (<code>n</code>)、<code>U+0072</code> (<code>r</code>) 或者 <code>U+0074</code> (<code>t</code>) 之一，依次分别表示 Unicode 码点 <code>U+000A</code>（LF），<code>U+000D</code>（CR），或者 <code>U+0009</code>（HT）。</li>
<li><em>null转义</em> 是字符 <code>U+0030</code>（<code>0</code>），表示 Unicode 码点 <code>U+0000</code>（NUL）。</li>
<li><em>反斜线转义</em> 是字符 <code>U+005C</code>（<code>\</code>），反斜线必须通过转义才能表示其自身。</li>
</ul>
<h4><a class="header" href="#raw-string-literals" id="raw-string-literals">Raw string literals</a></h4>
<h4><a class="header" href="#原生字符串字面量" id="原生字符串字面量">原生字符串字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
RAW_STRING_LITERAL :<br />
   <code>r</code> RAW_STRING_CONTENT</p>
<p>RAW_STRING_CONTENT :<br />
      <code>&quot;</code> ( ~ <em>IsolatedCR</em> )<sup>* (非贪婪模式)</sup> <code>&quot;</code><br />
   | <code>#</code> RAW_STRING_CONTENT <code>#</code></p>
</blockquote>
<p>原生字符串字面量不做任何转义。它以字符 <code>U+0072</code>（<code>r</code>）后跟零个或多个字符 <code>U+0023</code>（<code>#</code>），以及一个字符 <code>U+0022</code>（双引号 <code>&quot;</code>），这样的字符组合开始；中间<em>原生字符串文本主体</em>部分可包含任意的 Unicode 字符序列；再后跟另一个 <code>U+0022</code>（双引号 <code>&quot;</code>）字符表示文本主体结束；最后再后跟与文本主体前的那段字符组合中的同等数量的 <code>U+0023</code>（<code>#</code>）字符。</p>
<p>所有包含在原生字符串文本主体中的 Unicode 字符都代表他们自身：字符 <code>U+0022</code>（双引号 <code>&quot;</code>）（除非后跟的纯 <code>U+0023</code> (<code>#</code>)字符串与文本主体开始前的对称相等）或字符 <code>U+005C</code>（<code>\</code>）此时都没有特殊含义。</p>
<p>字符串字面量示例:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>&quot;foo&quot;; r&quot;foo&quot;;                     // foo
&quot;\&quot;foo\&quot;&quot;; r#&quot;&quot;foo&quot;&quot;#;             // &quot;foo&quot;

&quot;foo #\&quot;# bar&quot;;
r##&quot;foo #&quot;# bar&quot;##;                // foo #&quot;# bar

&quot;\x52&quot;; &quot;R&quot;; r&quot;R&quot;;                 // R
&quot;\\x52&quot;; r&quot;\x52&quot;;                  // \x52
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#byte-and-byte-string-literals" id="byte-and-byte-string-literals">Byte and byte string literals</a></h3>
<h3><a class="header" href="#字节和字节串字面量" id="字节和字节串字面量">字节和字节串字面量</a></h3>
<h4><a class="header" href="#byte-literals" id="byte-literals">Byte literals</a></h4>
<h4><a class="header" href="#字节字面量" id="字节字面量">字节字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
BYTE_LITERAL :<br />
   <code>b'</code> ( ASCII_FOR_CHAR | BYTE_ESCAPE )  <code>'</code></p>
<p>ASCII_FOR_CHAR :<br />
   <em>任何 ASCII 字符 （0x00 到 0x7F）, 排除</em> <code>'</code>, <code>\</code>, \n, \r 或者 \t</p>
<p>BYTE_ESCAPE :<br />
      <code>\x</code> HEX_DIGIT HEX_DIGIT<br />
   | <code>\n</code> | <code>\r</code> | <code>\t</code> | <code>\\</code> | <code>\0</code></p>
</blockquote>
<p><em>字节字面量</em>是单个 ASCII 字符（码值在 <code>U+0000</code> 到 <code>U+007F</code> 区间内）或一个<em>转义字节</em>作为字节字面量的真实主体跟在表示形式意义的字符 <code>U+0062</code>（<code>b</code>）和字符 <code>U+0027</code>（单引号 <code>'</code>）组合之后，然后再后接字符 <code>U+0027</code>。如果字符 <code>U+0027</code> 本身要出现在字面量中，它必须经由前置字符 <code>U+005C</code>（<code>\</code>）<em>转义</em>。字节字面量等价于一个 <code>u8</code> 8-bit 无符号整型<em>数字字面量</em>。</p>
<h4><a class="header" href="#byte-string-literals" id="byte-string-literals">Byte string literals</a></h4>
<h4><a class="header" href="#字节串字面量" id="字节串字面量">字节串字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
BYTE_STRING_LITERAL :<br />
   <code>b&quot;</code> ( ASCII_FOR_STRING | BYTE_ESCAPE | STRING_CONTINUE )<sup>*</sup> <code>&quot;</code></p>
<p>ASCII_FOR_STRING :<br />
   <em>任何 ASCII 字符(码值位于 0x00 到 0x7F 之间), 排除</em> <code>&quot;</code>, <code>\</code> <em>和 IsolatedCR</em></p>
</blockquote>
<p>非原生<em>字节串字面量</em>是 ASCII 字符和转义字符组成的字符序列，形式是以字符 <code>U+0062</code>（<code>b</code>）和字符 <code>U+0022</code>（双引号 <code>&quot;</code>）组合开头，以字符 <code>U+0022</code> 结尾。如果字面量中包含字符 <code>U+0022</code>，则必须由前置的 <code>U+005C</code>（<code>\</code>）<em>转义</em>。此外，字节串字面量也可以是<em>原生字节串字面量</em>（下面有其定义）。长度为 <code>n</code> 的字节串字面量类型为 <code>&amp;'static [u8; n]</code>。</p>
<p>一些额外的<em>转义</em>可以在字节或非原生字节串字面量中使用，转义以 <code>U+005C</code>（<code>\</code>）开始，并后跟如下形式之一：</p>
<ul>
<li><em>字节转义</em>以 <code>U+0078</code> (<code>x</code>)开始，后跟恰好两位<em>十六进制数字</em>来表示十六进制值代表的字节。</li>
<li><em>空白符转义</em>是字符 <code>U+006E</code>（<code>n</code>）、<code>U+0072</code>（<code>r</code>），或 <code>U+0074</code>（<code>t</code>）之一，分别表示字节值 <code>0x0A</code>（ASCII LF）、<code>0x0D</code>（ASCII CR），或 <code>0x09</code>（ASCII HT）。</li>
<li><em>null转义</em>是字符 <code>U+0030</code>（<code>0</code>），表示字节值 <code>0x00</code> （ASCII NUL）。</li>
<li><em>反斜线转义</em>是字符 <code>U+005C</code>（<code>\</code>），必须被转义以表示其 ASCII 编码 <code>0x5C</code>。</li>
</ul>
<h4><a class="header" href="#raw-byte-string-literals" id="raw-byte-string-literals">Raw byte string literals</a></h4>
<h4><a class="header" href="#原生字节串字面量" id="原生字节串字面量">原生字节串字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
RAW_BYTE_STRING_LITERAL :<br />
   <code>br</code> RAW_BYTE_STRING_CONTENT</p>
<p>RAW_BYTE_STRING_CONTENT :<br />
      <code>&quot;</code> ASCII<sup>* (非贪婪模式)</sup> <code>&quot;</code><br />
   | <code>#</code> RAW_BYTE_STRING_CONTENT <code>#</code></p>
<p>ASCII :<br />
   <em>任何 ASCII 字符（0x00 到 0x7F）</em></p>
</blockquote>
<p>原生字节串字面量不做任何转义。它们以字符 <code>U+0062</code>（<code>b</code>）后跟 <code>U+0072</code>（<code>r</code>），再后跟零个或多个字符 <code>U+0023</code>（<code>#</code>）及字符 <code>U+0022</code>（双引号 <code>&quot;</code>），这样的字符组合开始；之后是<em>原生字节串文本主体</em>，这部分可包含任意的 ASCII 字符序列；后跟另一个 <code>U+0022</code>（双引号 <code>&quot;</code>）字符表示文本主体结束；最后再后跟与文本主体前的那段字符组合中的同等数量的 <code>U+0023</code>（<code>#</code>）字符。原生字节串字面量不能包含任何非 ASCII 字节。</p>
<p>原生字节串文本主体中的所有字符都代表它们自身的 ASCII 编码，字符 <code>U+0022</code>（双引号 <code>&quot;</code>）（除非后跟的纯 <code>U+0023</code>（<code>#</code>）字符串与文本主体开始前的对称相等）或字符 <code>U+005C</code>（<code>\</code>）此时都没有特殊含义。</p>
<p>字节串字面量示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>b&quot;foo&quot;; br&quot;foo&quot;;                     // foo
b&quot;\&quot;foo\&quot;&quot;; br#&quot;&quot;foo&quot;&quot;#;             // &quot;foo&quot;

b&quot;foo #\&quot;# bar&quot;;
br##&quot;foo #&quot;# bar&quot;##;                 // foo #&quot;# bar

b&quot;\x52&quot;; b&quot;R&quot;; br&quot;R&quot;;                // R
b&quot;\\x52&quot;; br&quot;\x52&quot;;                  // \x52
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#number-literals" id="number-literals">Number literals</a></h3>
<h3><a class="header" href="#数字字面量" id="数字字面量">数字字面量</a></h3>
<p><em>数字字面量</em>可以是<em>整型字面量</em>，也可以是<em>浮点型字面量</em>，识别这两种字面量的文法是混合在一起的。</p>
<h4><a class="header" href="#integer-literals" id="integer-literals">Integer literals</a></h4>
<h4><a class="header" href="#整型字面量" id="整型字面量">整型字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
INTEGER_LITERAL :<br />
   ( DEC_LITERAL | BIN_LITERAL | OCT_LITERAL | HEX_LITERAL )
INTEGER_SUFFIX<sup>?</sup></p>
<p>DEC_LITERAL :<br />
   DEC_DIGIT (DEC_DIGIT|<code>_</code>)<sup>*</sup></p>
<p>BIN_LITERAL :<br />
   <code>0b</code> (BIN_DIGIT|<code>_</code>)<sup>*</sup> BIN_DIGIT (BIN_DIGIT|<code>_</code>)<sup>*</sup></p>
<p>OCT_LITERAL :<br />
   <code>0o</code> (OCT_DIGIT|<code>_</code>)<sup>*</sup> OCT_DIGIT (OCT_DIGIT|<code>_</code>)<sup>*</sup></p>
<p>HEX_LITERAL :<br />
   <code>0x</code> (HEX_DIGIT|<code>_</code>)<sup>*</sup> HEX_DIGIT (HEX_DIGIT|<code>_</code>)<sup>*</sup></p>
<p>BIN_DIGIT : [<code>0</code>-<code>1</code>]</p>
<p>OCT_DIGIT : [<code>0</code>-<code>7</code>]</p>
<p>DEC_DIGIT : [<code>0</code>-<code>9</code>]</p>
<p>HEX_DIGIT : [<code>0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F</code>]</p>
<p>INTEGER_SUFFIX :<br />
      <code>u8</code> | <code>u16</code> | <code>u32</code> | <code>u64</code> | <code>u128</code> | <code>usize</code><br />
   | <code>i8</code> | <code>i16</code> | <code>i32</code> | <code>i64</code> | <code>i128</code> | <code>isize</code></p>
</blockquote>
<p><em>整型字面量</em>具备下述 4 种形式之一：</p>
<ul>
<li><em>十进制字面量</em>以<em>十进制数字</em>开头，后跟<em>十进制数字</em>和*下划线(<code>_</code>)*的任意组合。</li>
<li><em>十六进制字面量</em>以字符序列 <code>U+0030</code> <code>U+0078</code>（<code>0x</code>）开头，后跟十六进制数字和下划线的任意组合（至少一个数字）。</li>
<li><em>八进制字面量</em>以字符序列 <code>U+0030</code> <code>U+006F</code>（<code>0o</code>）开头，后跟八进制数字和下划线的任意组合（至少一个数字）。</li>
<li><em>二进制字面量</em>以字符序列 <code>U+0030</code> <code>U+0062</code>（<code>0b</code>）开头，后跟二进制数字和下划线的任意组合（至少一个数字）。</li>
</ul>
<p>与其它字面量一样，整型字面量后面可紧跟一个<em>整型后缀</em>，该后缀强制设定了字面量的数据类型。整型后缀须为如下整型类型之一：<code>u8</code>、<code>i8</code>、<code>u16</code>、<code>i16</code>、<code>u32</code>、<code>i32</code>、<code>u64</code>、<code>i64</code>、<code>u128</code>、<code>i128</code>、<code>usize</code> 或 <code>isize</code>。</p>
<p><em>无后缀</em>整型字面量的类型通过类型推断确定：</p>
<ul>
<li>如果整型类型可以通过程序上下文<em>唯一</em>确定，则无后缀整型字面量的类型即为该类型。</li>
<li>如果程序上下文对类型约束不足，则默认为 32-bit 有符号整型，即 <code>i32</code>。</li>
<li>如果程序上下文对类型约束过度，则报静态类型错误。</li>
</ul>
<p>各种形式的整型字面量示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>123;                               // 类型 i32
123i32;                            // 类型 i32
123u32;                            // 类型 u32
123_u32;                           // 类型 u32
let a: u64 = 123;                  // 类型 u64

0xff;                              // 类型 i32
0xff_u8;                           // 类型 u8

0o70;                              // 类型 i32
0o70_i16;                          // 类型 i16

0b1111_1111_1001_0000;             // 类型 i32
0b1111_1111_1001_0000i64;          // 类型 i64
0b________1;                       // 类型 i32

0usize;                            // 类型 usize
<span class="boring">}
</span></code></pre></pre>
<p>无效整型字面量示例:</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 无效后缀

0invalidSuffix;

// 数字进制错误

123AFB43;
0b0102;
0o0581;

// 类型溢出

128_i8;
256_u8;

// 二进制、十六进制、八进制的进制前缀后至少需要一个数字

0b_;
0b____;
<span class="boring">}
</span></code></pre></pre>
<p>请注意，Rust 句法将 <code>-1i8</code> 视为<a href="expressions/operator-expr.html#negation-operators">一元取反运算符</a>对整型字面量 <code>1i8</code> 的应用，而不是将它视为单个整型字面量。</p>
<h4><a class="header" href="#tuple-index" id="tuple-index">Tuple index</a></h4>
<h4><a class="header" href="#元组索引" id="元组索引">元组索引</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
TUPLE_INDEX: <br />
   INTEGER_LITERAL</p>
</blockquote>
<p>元组索引用于引用<a href="types/tuple.html">元组</a>、<a href="items/structs.html">元组结构体</a>和<a href="items/enumerations.html">元组变体</a>的字段。</p>
<p>元组索引直接与字面量token 进行比较。元组索引以 <code>0</code> 开始，每个后续索引的值以十进制的 <code>1</code> 递增。因此，元组索引只能匹配十进制值，并且该值不能用 <code>0</code> 做前缀字符。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let example = (&quot;dog&quot;, &quot;cat&quot;, &quot;horse&quot;);
let dog = example.0;
let cat = example.1;
// 下面的示例非法.
let cat = example.01;  // 错误：没有 `01` 字段
let horse = example.0b10;  // 错误：没有 `0b10` 字段
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><strong>注意</strong>: 元组索引可能包含一个 <code>INTEGER_SUFFIX</code> ，但是这不是有效的，可能会在将来的版本中被删除。更多信息请参见<a href="https://github.com/rust-lang/rust/issues/60210">https://github.com/rust-lang/rust/issues/60210</a>。</p>
</blockquote>
<h4><a class="header" href="#floating-point-literals" id="floating-point-literals">Floating-point literals</a></h4>
<h4><a class="header" href="#浮点型字面量" id="浮点型字面量">浮点型字面量</a></h4>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
FLOAT_LITERAL :<br />
      DEC_LITERAL <code>.</code>
<em>（紧跟着的不能是 <code>.</code>, <code>_</code> 或者<a href="identifiers.html">标识符</a>）</em><br />
   | DEC_LITERAL FLOAT_EXPONENT<br />
   | DEC_LITERAL <code>.</code> DEC_LITERAL FLOAT_EXPONENT<sup>?</sup><br />
   | DEC_LITERAL (<code>.</code> DEC_LITERAL)<sup>?</sup>
FLOAT_EXPONENT<sup>?</sup> FLOAT_SUFFIX</p>
<p>FLOAT_EXPONENT :<br />
   (<code>e</code>|<code>E</code>) (<code>+</code>|<code>-</code>)?
(DEC_DIGIT|<code>_</code>)<sup>*</sup> DEC_DIGIT (DEC_DIGIT|<code>_</code>)<sup>*</sup></p>
<p>FLOAT_SUFFIX :<br />
   <code>f32</code> | <code>f64</code></p>
</blockquote>
<p><em>浮点型字面量</em>有如下两种形式：</p>
<ul>
<li><em>十进制字面量</em>后跟句点字符 <code>U+002E</code> (<code>.</code>)。后面可选地跟着另一个十进制数字，还可以再接一个可选的<em>指数</em>。</li>
<li><em>十进制字面量</em>后跟一个<em>指数</em>。</li>
</ul>
<p>如同整型字面量，浮点型字面量也可后跟一个后缀，但在后缀之前，浮点型字面量部分不以 <code>U+002E</code>（<code>.</code>）结尾。后缀强制设定了字面量类型。有两种有效的<em>浮点型后缀</em>：<code>f32</code> 和 <code>f64</code>（32-bit 和 64-bit 浮点类型），它们显式地指定了字面量的类型。</p>
<ul>
<li>
<p>If the program context under-constrains the type, it defaults to <code>f64</code>.</p>
</li>
<li>
<p>If the program context over-constrains the type, it is considered a
static type error.
<em>无后缀</em>浮点型字面量的类型通过类型推断确定：</p>
</li>
<li>
<p>如果浮点型类型可以通过程序上下文<em>唯一</em>确定，则无后缀浮点型字面量的类型即为该类型。</p>
</li>
<li>
<p>如果程序上下文对类型约束不足，则默认为 <code>f64</code>。</p>
</li>
<li>
<p>如果程序上下文对类型过度约束，则报静态类型错误。</p>
</li>
</ul>
<p>各种形式的浮点型字面量示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>123.0f64;        // 类型 f64
0.1f64;          // 类型 f64
0.1f32;          // 类型 f32
12E+99_f64;      // 类型 f64
5f32;            // 类型 f32
let x: f64 = 2.; // 类型 f64
<span class="boring">}
</span></code></pre></pre>
<p>最后一个例子稍显不同，因为不能对一个以句点结尾的浮点型字面量使用后缀句法，<code>2.f64</code> 会尝试在 <code>2</code> 上调用名为 <code>f64</code> 的方法。</p>
<p>浮点数的表形(representation)语义在<a href="types/numeric.html">“和平台相关的类型”</a>中有描述。</p>
<h3><a class="header" href="#boolean-literals" id="boolean-literals">Boolean literals</a></h3>
<h3><a class="header" href="#布尔型字面量" id="布尔型字面量">布尔型字面量</a></h3>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
BOOLEAN_LITERAL :<br />
      <code>true</code><br />
   | <code>false</code></p>
</blockquote>
<p>布尔类型有两个值，写为：<code>true</code> 和 <code>false</code>。</p>
<h2><a class="header" href="#lifetimes-and-loop-labels" id="lifetimes-and-loop-labels">Lifetimes and loop labels</a></h2>
<h2><a class="header" href="#生存期和循环标签" id="生存期和循环标签">生存期和循环标签</a></h2>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
LIFETIME_TOKEN :<br />
      <code>'</code> <a href="identifiers.html">IDENTIFIER_OR_KEYWORD</a><br />
   | <code>'_</code></p>
<p>LIFETIME_OR_LABEL :<br />
      <code>'</code> <a href="identifiers.html">NON_KEYWORD_IDENTIFIER</a></p>
</blockquote>
<p>生存期参数和<a href="expressions/loop-expr.html">循环标签</a>使用 LIFETIME_OR_LABEL 类型的 token。（尽管 LIFETIME_OR_LABEL 是 LIFETIME_TOKEN 的子集，但）任何符合 LIFETIME_TOKEN 约定的 token 也都能被上述词法分析规则所接受，比如 LIFETIME_TOKEN 类型的 token 在宏中就可以畅通无阻的使用。</p>
<h2><a class="header" href="#punctuation" id="punctuation">Punctuation</a></h2>
<h2><a class="header" href="#标点符号" id="标点符号">标点符号</a></h2>
<p>为了完整起见，这里列出了（Rust 里）所有的标点符号的 symbol token。它们各自的用法和含义在链接页面中都有定义。</p>
<table><thead><tr><th>符号</th><th>名称</th><th>使用方法</th></tr></thead><tbody>
<tr><td><code>+</code></td><td>Plus</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术加法</a>, <a href="trait-bounds.html">trait约束</a>, <a href="macros-by-example.html">可匹配空的宏匹配器</a>(Macro Kleene Matcher)</td></tr>
<tr><td><code>-</code></td><td>Minus</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术减法</a>, <a href="expressions/operator-expr.html#negation-operators">取反</a></td></tr>
<tr><td><code>*</code></td><td>Star</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术乘法</a>, <a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>, <a href="types/pointer.html#raw-pointers-const-and-mut">裸指针</a>, <a href="macros-by-example.html">可匹配空的宏匹配器</a>, <a href="items/use-declarations.html">use 通配符</a></td></tr>
<tr><td><code>/</code></td><td>Slash</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术除法</a></td></tr>
<tr><td><code>%</code></td><td>Percent</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术取模</a></td></tr>
<tr><td><code>^</code></td><td>Caret</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">位和逻辑异或</a></td></tr>
<tr><td><code>!</code></td><td>Not</td><td><a href="expressions/operator-expr.html#negation-operators">位和逻辑非</a>, <a href="macros-by-example.html">宏调用</a>, <a href="attributes.html">内部属性</a>, <a href="types/never.html">never型</a>, <a href="items/implementations.html">否定实现</a></td></tr>
<tr><td><code>&amp;</code></td><td>And</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">位和逻辑与</a>, <a href="expressions/operator-expr.html#borrow-operators">借用</a>, <a href="types/pointer.html">引用</a>, <a href="patterns.html#reference-patterns">引用模式</a></td></tr>
<tr><td><code>|</code></td><td>Or</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">位和逻辑或</a>, <a href="expressions/closure-expr.html">闭包</a>, <a href="expressions/match-expr.html">match</a> 中的模式, <a href="expressions/if-expr.html#if-let-expressions"><code>if let</code></a>, 和 <a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a></td></tr>
<tr><td><code>&amp;&amp;</code></td><td>AndAnd</td><td><a href="expressions/operator-expr.html#lazy-boolean-operators">短路与</a>, <a href="expressions/operator-expr.html#borrow-operators">借用</a>, <a href="types/pointer.html">引用</a>, <a href="patterns.html#reference-patterns">引用模式</a></td></tr>
<tr><td><code>||</code></td><td>OrOr</td><td><a href="expressions/operator-expr.html#lazy-boolean-operators">短路或</a>, <a href="expressions/closure-expr.html">闭包</a></td></tr>
<tr><td><code>&lt;&lt;</code></td><td>Shl</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">左移位</a>, <a href="items/generics.html">嵌套泛型</a></td></tr>
<tr><td><code>&gt;&gt;</code></td><td>Shr</td><td><a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">右移位</a>, <a href="items/generics.html">嵌套泛型</a></td></tr>
<tr><td><code>+=</code></td><td>PlusEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">加法及赋值</a></td></tr>
<tr><td><code>-=</code></td><td>MinusEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">减法及赋值</a></td></tr>
<tr><td><code>*=</code></td><td>StarEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">乘法及赋值</a></td></tr>
<tr><td><code>/=</code></td><td>SlashEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">除法及赋值</a></td></tr>
<tr><td><code>%=</code></td><td>PercentEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">取模及赋值</a></td></tr>
<tr><td><code>^=</code></td><td>CaretEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">按位异或及赋值</a></td></tr>
<tr><td><code>&amp;=</code></td><td>AndEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">按位与及赋值</a></td></tr>
<tr><td><code>|=</code></td><td>OrEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">按位或及赋值</a></td></tr>
<tr><td><code>&lt;&lt;=</code></td><td>ShlEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">左移位及赋值</a></td></tr>
<tr><td><code>&gt;&gt;=</code></td><td>ShrEq</td><td><a href="expressions/operator-expr.html#compound-assignment-expressions">右移位及赋值</a>, <a href="items/generics.html">嵌套泛型</a></td></tr>
<tr><td><code>=</code></td><td>Eq</td><td><a href="expressions/operator-expr.html#assignment-expressions">赋值</a>, <a href="attributes.html">属性</a>, 各种类型定义</td></tr>
<tr><td><code>==</code></td><td>EqEq</td><td><a href="expressions/operator-expr.html#comparison-operators">等于</a></td></tr>
<tr><td><code>!=</code></td><td>Ne</td><td><a href="expressions/operator-expr.html#comparison-operators">不等于</a></td></tr>
<tr><td><code>&gt;</code></td><td>Gt</td><td><a href="expressions/operator-expr.html#comparison-operators">大于</a>, <a href="items/generics.html">泛型</a>, <a href="paths.html">路径</a></td></tr>
<tr><td><code>&lt;</code></td><td>Lt</td><td><a href="expressions/operator-expr.html#comparison-operators">小于</a>, <a href="items/generics.html">泛型</a>, <a href="paths.html">路径</a></td></tr>
<tr><td><code>&gt;=</code></td><td>Ge</td><td><a href="expressions/operator-expr.html#comparison-operators">大于或等于</a>, <a href="items/generics.html">泛型</a></td></tr>
<tr><td><code>&lt;=</code></td><td>Le</td><td><a href="expressions/operator-expr.html#comparison-operators">小于或等于</a></td></tr>
<tr><td><code>@</code></td><td>At</td><td><a href="patterns.html#identifier-patterns">子模式绑定</a></td></tr>
<tr><td><code>_</code></td><td>Underscore</td><td><a href="patterns.html#wildcard-pattern">通配符模式</a>, <a href="types/inferred.html">自动推断型类型</a>, <a href="items/constant-items.html">常量项</a>中的非命名程序项, <a href="items/extern-crates.html">外部 crate</a>, 和 <a href="items/use-declarations.html">use声明</a></td></tr>
<tr><td><code>.</code></td><td>Dot</td><td><a href="expressions/field-expr.html">字段访问</a>, <a href="expressions/tuple-expr.html#tuple-indexing-expressions">元组索引</a></td></tr>
<tr><td><code>..</code></td><td>DotDot</td><td><a href="expressions/range-expr.html">区间</a>, <a href="expressions/struct-expr.html">结构体表达式</a>, <a href="patterns.html">模式</a></td></tr>
<tr><td><code>...</code></td><td>DotDotDot</td><td><a href="items/external-blocks.html">可变参数函数</a>, <a href="patterns.html#range-patterns">区间模式</a></td></tr>
<tr><td><code>..=</code></td><td>DotDotEq</td><td><a href="expressions/range-expr.html">闭区间</a>, <a href="patterns.html#range-patterns">区间模式</a></td></tr>
<tr><td><code>,</code></td><td>Comma</td><td>各种分隔符</td></tr>
<tr><td><code>;</code></td><td>Semi</td><td>各种程序项和语句的结束符, <a href="types/array.html">数组类型</a></td></tr>
<tr><td><code>:</code></td><td>Colon</td><td>各种分隔符</td></tr>
<tr><td><code>::</code></td><td>PathSep</td><td>[路径分隔符]<a href="paths.html">路径</a></td></tr>
<tr><td><code>-&gt;</code></td><td>RArrow</td><td><a href="items/functions.html">函数返回类型</a>, <a href="expressions/closure-expr.html">闭包返回类型</a>, <a href="types/function-pointer.html">数组指针类型</a></td></tr>
<tr><td><code>=&gt;</code></td><td>FatArrow</td><td><a href="expressions/match-expr.html">匹配臂</a>, <a href="macros-by-example.html">宏</a></td></tr>
<tr><td><code>#</code></td><td>Pound</td><td><a href="attributes.html">属性</a></td></tr>
<tr><td><code>$</code></td><td>Dollar</td><td><a href="macros-by-example.html">宏</a></td></tr>
<tr><td><code>?</code></td><td>Question</td><td><a href="expressions/operator-expr.html#the-question-mark-operator">问号运算符</a>, <a href="trait-bounds.html#sized">非确定性尺寸</a>, <a href="macros-by-example.html">可匹配空的宏匹配器</a></td></tr>
</tbody></table>
<h2><a class="header" href="#delimiters" id="delimiters">Delimiters</a></h2>
<h2><a class="header" href="#定界符" id="定界符">定界符</a></h2>
<p>括号用于文法的各个部分，左括号必须始终与右括号配对。括号以及其内的 token 在<a href="macros-by-example.html">宏</a>中被称作“token树(token trees)”。括号有三种类型：</p>
<table><thead><tr><th>括号</th><th>类型</th></tr></thead><tbody>
<tr><td><code>{</code> <code>}</code></td><td>花/大括号</td></tr>
<tr><td><code>[</code> <code>]</code></td><td>方/中括号</td></tr>
<tr><td><code>(</code> <code>)</code></td><td>圆/小括号</td></tr>
</tbody></table>
<!-- 2020-11-12-->
<!-- checked --><h1><a class="header" href="#macros" id="macros">Macros</a></h1>
<h1><a class="header" href="#宏" id="宏">宏</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/macros.md">macros.md</a><br />
commit: 012bfafbd995c54a86ebb542bbde5874710cba19 <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<p>可以使用称被为宏的自定义句法形式来扩展 Rust 的功能和句法。宏需要被命名，并通过一致的句法去调用：<code>some_extension!(...)</code>。</p>
<p>定义新宏有两种方式：</p>
<ul>
<li><a href="macros-by-example.html">声明宏(Macros by Example)</a>以更高级别的声明性的方式定义了一套新句法规则。</li>
<li><a href="procedural-macros.html">过程宏(Procedural Macros)</a>使用操作输入标记符的函数来定义类函数宏、自定义派生和自定义属性。</li>
</ul>
<h2><a class="header" href="#macro-invocation" id="macro-invocation">Macro Invocation</a></h2>
<h2><a class="header" href="#宏调用" id="宏调用">宏调用</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MacroInvocation</em> :<br />
   <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>!</code> <em>DelimTokenTree</em></p>
<p><em>DelimTokenTree</em> :<br />
       <code>(</code> <em>TokenTree</em><sup>*</sup> <code>)</code><br />
   | <code>[</code> <em>TokenTree</em><sup>*</sup> <code>]</code><br />
   | <code>{</code> <em>TokenTree</em><sup>*</sup> <code>}</code></p>
<p><em>TokenTree</em> :<br />
   <a href="tokens.html"><em>Token</em></a><sub><em>排除 <a href="tokens.html#delimiters">定界符(delimiters)</a></em></sub> | <em>DelimTokenTree</em></p>
<p><em>MacroInvocationSemi</em> :<br />
      <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>!</code> <code>(</code> <em>TokenTree</em><sup>*</sup> <code>)</code> <code>;</code><br />
   | <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>!</code> <code>[</code> <em>TokenTree</em><sup>*</sup> <code>]</code> <code>;</code><br />
   | <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>!</code> <code>{</code> <em>TokenTree</em><sup>*</sup> <code>}</code></p>
</blockquote>
<p>宏调用是在编译时扩展宏，并用扩展结果替换该调用。可以在下述情况里调用宏：</p>
<ul>
<li><a href="expressions.html">表达式</a>和<a href="statements.html">语句</a></li>
<li><a href="patterns.html">模式</a></li>
<li><a href="types.html">类型</a></li>
<li><a href="items.html">程序项</a>，包括<a href="items/associated-items.html">关联程序项</a></li>
<li><a href="macros-by-example.html"><code>macro_rules</code></a> 转码器</li>
<li><a href="items/external-blocks.html">外部块</a></li>
</ul>
<p>当宏调用被用作程序项或语句时，此时它应用的 <em>MacroInvocationSemi</em> 句法规则要求它如果不使用花括号，则在结尾处须添加分号。在宏调用或<a href="macros-by-example.html">宏(<code>macro_rules</code>)</a>定义之前不允许使用<a href="visibility-and-privacy.html">可见性限定符</a>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 作为表达式使用.
let x = vec![1,2,3];

// 作为语句使用.
println!(&quot;Hello!&quot;);

// 在模式中使用.
macro_rules! pat {
    ($i:ident) =&gt; (Some($i))
}

if let pat!(x) = Some(1) {
    assert_eq!(x, 1);
}

// 在类型中使用.
macro_rules! Tuple {
    { $A:ty, $B:ty } =&gt; { ($A, $B) };
}

type N2 = Tuple!(i32, i32);

// 作为程序项使用.
<span class="boring">use std::cell::RefCell;
</span>thread_local!(static FOO: RefCell&lt;u32&gt; = RefCell::new(1));

// 作为关联程序项使用.
macro_rules! const_maker {
    ($t:ty, $v:tt) =&gt; { const CONST: $t = $v; };
}
trait T {
    const_maker!{i32, 7}
}

// 宏内调用宏
macro_rules! example {
    () =&gt; { println!(&quot;Macro call in a macro!&quot;) };
}
// 外部宏 `example` 展开后, 内部宏 `println` 才会展开.
example!();
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked --><h1><a class="header" href="#macros-by-example" id="macros-by-example">Macros By Example</a></h1>
<h1><a class="header" href="#声明宏" id="声明宏">声明宏</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/macros-by-example.md">macros-by-example.md</a><br />
commit: 3a6ddea02244857362ac05d85ec98736b738c0ff <br />
本章译文最后维护日期：2021-5-29</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MacroRulesDefinition</em> :<br />
   <code>macro_rules</code> <code>!</code> <a href="identifiers.html">IDENTIFIER</a> <em>MacroRulesDef</em></p>
<p><em>MacroRulesDef</em> :<br />
      <code>(</code> <em>MacroRules</em> <code>)</code> <code>;</code><br />
   | <code>[</code> <em>MacroRules</em> <code>]</code> <code>;</code><br />
   | <code>{</code> <em>MacroRules</em> <code>}</code></p>
<p><em>MacroRules</em> :<br />
   <em>MacroRule</em> ( <code>;</code> <em>MacroRule</em> )<sup>*</sup> <code>;</code><sup>?</sup></p>
<p><em>MacroRule</em> :<br />
   <em>MacroMatcher</em> <code>=&gt;</code> <em>MacroTranscriber</em></p>
<p><em>MacroMatcher</em> :<br />
      <code>(</code> <em>MacroMatch</em><sup>*</sup> <code>)</code><br />
   | <code>[</code> <em>MacroMatch</em><sup>*</sup> <code>]</code><br />
   | <code>{</code> <em>MacroMatch</em><sup>*</sup> <code>}</code></p>
<p><em>MacroMatch</em> :<br />
      <a href="tokens.html"><em>Token</em></a><sub><em>排除 $ 和 定界符</em></sub><br />
   | <em>MacroMatcher</em><br />
   | <code>$</code> <a href="identifiers.html">IDENTIFIER</a> <code>:</code> <em>MacroFragSpec</em><br />
   | <code>$</code> <code>(</code> <em>MacroMatch</em><sup>+</sup> <code>)</code> <em>MacroRepSep</em><sup>?</sup> <em>MacroRepOp</em></p>
<p><em>MacroFragSpec</em> :<br />
      <code>block</code> | <code>expr</code> | <code>ident</code> | <code>item</code> | <code>lifetime</code> | <code>literal</code><br />
   | <code>meta</code> | <code>pat</code> | <code>pat_param</code> | <code>path</code> | <code>stmt</code> | <code>tt</code> | <code>ty</code> | <code>vis</code></p>
<p><em>MacroRepSep</em> :<br />
   <a href="tokens.html"><em>Token</em></a><sub><em>排除 定界符 和 重复操作符</em></sub></p>
<p><em>MacroRepOp</em> :<br />
   <code>*</code> | <code>+</code> | <code>?</code></p>
<p><em>MacroTranscriber</em> :<br />
   <a href="macros.html"><em>DelimTokenTree</em></a></p>
</blockquote>
<p><code>macro_rules</code> 允许用户以声明性的(declarative)方式定义句法扩展。我们称这种扩展形式为“声明宏（macros by example）”或简称“宏”。</p>
<p>每个声明宏都有一个名称和一条或多条<em>规则</em>。每条规则都有两部分：一个<em>匹配器(matcher)</em>，描述它匹配的句法；一个<em>转码器(transcriber)</em>，描述成功匹配后将执行的替代调用句法。匹配器和转码器都必须由定界符(delimiter)包围。宏可以扩展为表达式、语句、程序项（包括 trait、impl 和外来程序项）、类型或模式。</p>
<h2><a class="header" href="#transcribing" id="transcribing">Transcribing</a></h2>
<h2><a class="header" href="#转码" id="转码">转码</a></h2>
<p>当宏被调用时，宏扩展器(macro expander)按名称查找宏调用，并依次尝试此宏中的每条宏规则。宏会根据第一个成功的匹配进行转码；如果当前转码结果导致错误，不会再尝试进行后续匹配。在匹配时，不会执行预判；如果编译器不能明确地确定如何一个 token 一个 token 地解析宏调用，则会报错。在下面的示例中，编译器不会越过标识符，去提前查看后跟的 token 是 <code>)</code>，尽管这能帮助它明确地解析调用：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! ambiguity {
    ($($i:ident)* $j:ident) =&gt; { };
}

ambiguity!(error); // 错误: 局部歧义(local ambiguity)
<span class="boring">}
</span></code></pre></pre>
<p>在匹配器和转码器中，token <code>$</code> 用于从宏引擎中调用特殊行为（下文<a href="macros-by-example.html#metavariables">元变量</a>和<a href="macros-by-example.html#repetitions">重复元</a>中有详述）。不属于此类调用的 token 将按字面意义进行匹配和转码，除了一个例外。这个例外是匹配器的外层定界符将匹配任何一对定界符。因此，比如匹配器 <code>(())</code> 将匹配 <code>{()}</code>，而 <code>{{}}</code> 不行。字符 <code>$</code> 不能按字面意义匹配或转码。</p>
<p>当将当前匹配的匹配段转发给另一个声明宏时，第二个宏中的匹配器看到的将是此匹配段类型的不透明抽象句法树(opaque AST)。第二个宏不能使用字面量token 来匹配匹配器中的这个匹配段，唯一可看到/使用的就是此匹配段类型一样的匹配段选择器(fragment specifier)。但匹配段类型 <code>ident</code>、<code>lifetime</code>、和 <code>tt</code> 是几个例外，它们<em>可以</em>通过字面量token 进行匹配。下面示例展示了这一限制：（译者注：匹配段选择器和匹配段，以及宏中各部件的定义可以凑合着看看译者未能翻译完成的<a href="macro-ambiguity.html">宏定义规范</a>）</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! foo {
    ($l:expr) =&gt; { bar!($l); }
// ERROR:               ^^ no rules expected this token in macro call
}

macro_rules! bar {
    (3) =&gt; {}
}

foo!(3);
<span class="boring">}
</span></code></pre></pre>
<p>以下示例展示了 <code>tt</code> 类型的匹配段在成功匹配（转码）一次之后生成的 tokens 如何能够再次直接匹配：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 成功编译
macro_rules! foo {
    ($l:tt) =&gt; { bar!($l); }
}

macro_rules! bar {
    (3) =&gt; {}
}

foo!(3);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#metavariables" id="metavariables">Metavariables</a></h2>
<h2><a class="header" href="#元变量" id="元变量">元变量</a></h2>
<p>在匹配器中，<code>$</code><em>名称</em><code>:</code><em>匹配段选择器</em> 这种句法格式匹配符合指定句法类型的 Rust 句法段，并将其绑定到元变量 <code>$</code><em>名称</em> 上。有效的匹配段选择器包括：</p>
<ul>
<li><code>item</code>: <a href="items.html"><em>程序项</em></a></li>
<li><code>block</code>: <a href="expressions/block-expr.html"><em>块表达式</em></a></li>
<li><code>stmt</code>: <a href="statements.html"><em>语句</em></a>，注意此选择器不匹配句尾的分号（如果匹配器中提供了分号，会被当做分隔符），但碰到分号是自身的一部分的程序项语句的情况又会匹配。</li>
<li><code>pat_param</code>: <a href="patterns.html"><em>模式</em></a></li>
<li><code>pat</code>: 等同于 <code>pat_param</code></li>
<li><code>expr</code>: <a href="expressions.html"><em>表达式</em></a></li>
<li><code>ty</code>: <a href="types.html#type-expressions"><em>类型</em></a></li>
<li><code>ident</code>: <a href="identifiers.html">标识符或关键字</a></li>
<li><code>path</code>: <a href="paths.html#paths-in-types"><em>类型表达式</em></a> 形式的路径</li>
<li><code>tt</code>: <a href="macros.html#macro-invocation"><em>token树</em></a> (单个 <a href="tokens.html">token</a> 或宏匹配定界符 <code>()</code>、<code>[]</code> 或<code>{}</code> 中的标记)</li>
<li><code>meta</code>: <a href="attributes.html"><em>属性</em></a>，属性中的内容</li>
<li><code>lifetime</code>: <a href="tokens.html#lifetimes-and-loop-labels">生存期token</a></li>
<li><code>vis</code>: 可能为空的<a href="visibility-and-privacy.html"><em>可见性</em></a>限定符</li>
<li><code>literal</code>: 匹配 <code>-</code><sup>?</sup><a href="expressions/literal-expr.html"><em>字面量表达式</em></a></li>
</ul>
<p>因为匹配段类型已在匹配器中指定了，则在转码器中，元变量只简单地用 <code>$</code><em>名称</em> 这种形式来指代就行了。元变量最终将被替换为跟它们匹配上的句法元素。元变量关键字 <code>$crate</code> 可以用来指代当前的 crate（请参阅后面的<a href="macros-by-example.html#hygiene">卫生性(hygiene)</a>章节）。元变量可以被多次转码，也可以完全不转码。</p>
<h2><a class="header" href="#repetitions" id="repetitions">Repetitions</a></h2>
<h2><a class="header" href="#重复元" id="重复元">重复元</a></h2>
<p>在匹配器和转码器中，重复元被表示为：将需要重复的 token 放在 <code>$(</code>…<code>)</code> 内，然后后跟一个重复运算符(repetition operator)，这两者之间可以放置一个可选的分隔符(separator token)。分隔符可以是除定界符或重复运算符之外的任何 token，其中分号(<code>;</code>)和逗号(<code>,</code>)最常见。例如： <code>$( $i:ident ),*</code> 表示用逗号分隔的任何数量的标识符。嵌套的重复元是合法的。</p>
<p>重复运算符为：</p>
<ul>
<li><code>*</code> — 表示任意数量的重复元。</li>
<li><code>+</code> — 表示至少有一个重复元。</li>
<li><code>?</code> — 表示一个可选的匹配段，可以出现零次或一次。</li>
</ul>
<p>因为 <code>?</code> 表示最多出现一次，所以它不能与分隔符一起使用。</p>
<p>通过分隔符的分隔，重复的匹配段都会被匹配和转码为指定的数量的匹配段。元变量就和这些每个段中的重复元相匹配。例如，之前示例中的 <code>$( $i:ident ),*</code> 将 <code>$i</code> 去匹配列表中的所有标识符。</p>
<p>在转码过程中，重复元会受到额外的限制，以便于编译器知道该如何正确地扩展它们：</p>
<ol>
<li>在转码器中，元变量必须与它在匹配器中出现的次数、指示符类型以及其在重复元内的嵌套顺序都完全相同。因此，对于匹配器 <code>$( $i:ident ),*</code>，转码器 <code>=&gt; { $i }</code>, <code>=&gt; { $( $( $i)* )* }</code> 和 <code>=&gt; { $( $i )+ }</code> 都是非法的，但是 <code>=&gt; { $( $i );* }</code> 是正确的，它用分号分隔的标识符列表替换了逗号分隔的标识符列表。</li>
<li>转码器中的每个重复元必须至少包含一个元变量，以便确定扩展多少次。如果在同一个重复元中出现多个元变量，则它们必须绑定到相同数量的匹配段上，不能有的多，有的少。例如，<code>( $( $i:ident ),* ; $( $j:ident ),* ) =&gt; (( $( ($i,$j) ),* ))</code> 里，绑定到 <code>$j</code> 的匹配段的数量必须与绑定到 <code>$i</code> 上的相同。这意味着用 <code>(a, b, c; d, e, f)</code> 调用这个宏是合法的，并且可扩展到 <code>((a,d), (b,e), (c,f))</code>，但是 <code>(a, b, c; d, e)</code> 是非法的，因为前后绑定的数量不同。此要求适用于嵌套的重复元的每一层。</li>
</ol>
<h2><a class="header" href="#scoping-exporting-and-importing" id="scoping-exporting-and-importing">Scoping, Exporting, and Importing</a></h2>
<h2><a class="header" href="#作用域导出以及导入" id="作用域导出以及导入">作用域、导出以及导入</a></h2>
<p>由于历史原因，声明宏的作用域并不完全像各种程序项那样工作。宏有两种形式的作用域：文本作用域(textual scope)和基于路径的作用域(path-based scope)。文本作用域基于宏在源文件中（定义和使用所）出现的顺序，或是跨多个源文件出现的顺序，文本作用域是默认的作用域。（后本节面将进一步解释这个。）基于路径的作用域与其他程序项作用域的运行方式相同。宏的作用域、导出和导入主要由其属性控制。</p>
<p>当声明宏被非限定标识符(unqualified identifier)（非多段路径段组成的限定性路径）调用时，会首先在文本作用域中查找。如果文本作用域中没有任何结果，则继续在基于路径的作用域中查找。如果宏的名称由路径限定，则只在基于路径的作用域中查找。</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">use lazy_static::lazy_static; // 基于路径的导入.

macro_rules! lazy_static { // 文本定义.
    (lazy) =&gt; {};
}

lazy_static!{lazy} // 首先通过文本作用域来查找我们的宏.
self::lazy_static!{} // 忽略文本作用域查找，直接使用基于路径的查找方式找到一个导入的宏.
</code></pre>
<h3><a class="header" href="#textual-scope" id="textual-scope">Textual Scope</a></h3>
<h3><a class="header" href="#文本作用域" id="文本作用域">文本作用域</a></h3>
<p>文本作用域很大程度上取决于宏本身在源文件中的出现顺序，其工作方式与用 <code>let</code>语句声明的局部变量的作用域类似，只不过它可以直接位于模块下。当使用 <code>macro_rules!</code> 定义宏时，宏在定义之后进入其作用域（请注意，这不影响宏在定义中递归调用自己，因为宏调用的入口还是在定义之后的某次调用点上，此点开始的宏名称递归查找一定有效），在封闭它的作用域（通常是模块）结束时离开。文本作用域可以覆盖/进入子模块，甚至跨越多个文件：</p>
<!-- ignore: requires external modules -->
<pre><code class="language-rust ignore">//// src/lib.rs
mod has_macro {
    // m!{} // 报错: m 未在作用域内.

    macro_rules! m {
        () =&gt; {};
    }
    m!{} // OK: 在声明 m 后使用.

    mod uses_macro;
}

// m!{} // Error: m 未在作用域内.

//// src/has_macro/uses_macro.rs

m!{} // OK: m 在上层模块文件 src/lib.rs 中声明后使用
</code></pre>
<p>多次定义宏并不报错；除非超出作用域，否则最近的宏声明将屏蔽前一个。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! m {
    (1) =&gt; {};
}

m!(1);

mod inner {
    m!(1);

    macro_rules! m {
        (2) =&gt; {};
    }
    // m!(1); // 报错: 没有设定规则来匹配 '1'
    m!(2);

    macro_rules! m {
        (3) =&gt; {};
    }
    m!(3);
}

m!(1);
<span class="boring">}
</span></code></pre></pre>
<p>宏也可以在函数内部声明和使用，其工作方式类似：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn foo() {
    // m!(); // 报错: m 未在作用域内.
    macro_rules! m {
        () =&gt; {};
    }
    m!();
}


// m!(); // Error: m 未在作用域内.
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#the-macro_use-attribute" id="the-macro_use-attribute">The <code>macro_use</code> attribute</a></h3>
<h3><a class="header" href="#macro_use属性" id="macro_use属性"><code>macro_use</code>属性</a></h3>
<p><em><code>macro_use</code>属性</em>有两种用途。首先，它可以通过作用于模块的方式让模块内的宏的作用域在模块关闭时不结束：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[macro_use]
mod inner {
    macro_rules! m {
        () =&gt; {};
    }
}

m!();
<span class="boring">}
</span></code></pre></pre>
<p>其次，它可以用于从另一个 crate 里来导入宏，方法是将它附加到当前 crate 根模块中的 <code>extern crate</code> 声明前。以这种方式导入的宏会被导入到<a href="names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a>里，而不是直接文本导入，这意味着它们可以被任何其他同名宏屏蔽。虽然可以在导入语句之前使用 <code>#[macro_use]</code> 导入宏，但如果发生冲突，则最后导入的宏将胜出。可以使用可选的 <a href="attributes.html#meta-item-attribute-syntax"><em>MetaListIdents</em></a>元项属性句法指定要导入的宏列表；当将 <code>#[macro_use]</code> 应用于模块上时，则不支持此指定操作。</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">#[macro_use(lazy_static)] // 或者使用 #[macro_use] 来导入所有宏.
extern crate lazy_static;

lazy_static!{}
// self::lazy_static!{} // 报错: lazy_static 没在 `self` 中定义
</code></pre>
<p>要用 <code>#[macro_use]</code> 导入宏必须先使用 <code>#[macro_export]</code> 导出，下文会有讲解。</p>
<h3><a class="header" href="#path-based-scope" id="path-based-scope">Path-Based Scope</a></h3>
<h3><a class="header" href="#基于路径的作用域" id="基于路径的作用域">基于路径的作用域</a></h3>
<p>默认情况下，宏没有基于路径的作用域。但是如果该宏带有 <code>#[macro_export]</code> 属性，则相当于它在当前 crate 的根作用域的顶部被声明，它通常可以这样引用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>self::m!();
m!(); // OK: 基于路径的查找发现 m 在当前模块中有声明.

mod inner {
    super::m!();
    crate::m!();
}

mod mac {
    #[macro_export]
    macro_rules! m {
        () =&gt; {};
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>标有 <code>#[macro_export]</code> 的宏始终是 <code>pub</code> 的，以便可以通过路径或前面所述的 <code>#[macro_use]</code> 方式让其他 crate 来引用。</p>
<h2><a class="header" href="#hygiene" id="hygiene">Hygiene</a></h2>
<h2><a class="header" href="#卫生性" id="卫生性">卫生性</a></h2>
<p>默认情况下，宏中引用的所有标识符都按原样展开，并在宏的调用位置上去查找。如果宏引用的程序项或宏不在调用位置的作用域内，则这可能会导致问题。为了解决这个问题，可以替代在路径的开头使用元变量 <code>$crate</code>，强制在定义宏的 crate 中进行查找。</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">//// 在 `helper_macro` crate 中.
#[macro_export]
macro_rules! helped {
    // () =&gt; { helper!() } // 这可能会导致错误，因为 'helper' 在当前作用域之后才定义.
    () =&gt; { $crate::helper!() }
}

#[macro_export]
macro_rules! helper {
    () =&gt; { () }
}

//// 在另一个 crate 中使用.
// 注意没有导入 `helper_macro::helper`!
use helper_macro::helped;

fn unit() {
    helped!();
}
</code></pre>
<p>请注意，由于 <code>$crate</code> 指的是当前的（<code>$crate</code> 源码出现的）crate，因此在引用非宏程序项时，它必须与全限定模块路径一起使用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub mod inner {
    #[macro_export]
    macro_rules! call_foo {
        () =&gt; { $crate::inner::foo() };
    }

    pub fn foo() {}
}
<span class="boring">}
</span></code></pre></pre>
<p>此外，尽管 <code>$crate</code> 允许宏在扩展时引用其自身 crate 中的程序项，但它的使用对可见性没有影响（，或者说它的使用仍受可见性条件的约束）。引用的程序项或宏必须仍然在调用位置处可见。在下面的示例中，任何试图从此 crate 外部调用 <code>call_foo!()</code> 的行为都将失败，因为 <code>foo()</code> 不是公有的。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[macro_export]
macro_rules! call_foo {
    () =&gt; { $crate::foo() };
}

fn foo() {}
<span class="boring">}
</span></code></pre></pre>
<p>（译者注：原文给出的这个例子是能正常调用的，原文并没有给出在 crate 外部调用的例子）</p>
<blockquote>
<p><strong>版本&amp;版次差异</strong>：在 Rust 1.30 之前，<code>$crate</code> 和 <code>local_inner_macros</code>（后面会讲）不受支持。从该版本开始，它们与基于路径的宏导入（前面讲过）一起被添加进来，用以确保不需要在当前 crate 已经使用导入了某导出宏的情况下再额外手动导入此导出宏下面用到的辅助宏。如果要让 Rust 的早期版本编写的 crate 要使用辅助宏，需要修改为使用 <code>$crate</code> 或 <code>local_inner_macros</code>，以便与基于路径的导入一起工作。</p>
</blockquote>
<p>当一个宏被导出时，可以在 <code>#[macro_export]</code> 属性里添加 <code>local_inner_macros</code> 属性值，用以自动为该属性修饰的宏内包含的所有宏调用自动添加 <code>$crate::</code> 前缀。这主要是作为一个工具来迁移那些在引入 <code>$crate</code> 之前的版本编写的 Rust 代码，以便它们能与 Rust 2018 版中基于路径的宏导入一起工作。在使用新版本编写的代码中不鼓励使用它。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[macro_export(local_inner_macros)]
macro_rules! helped {
    () =&gt; { helper!() } // 自动转码为 $crate::helper!().
}

#[macro_export]
macro_rules! helper {
    () =&gt; { () }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#follow-set-ambiguity-restrictions" id="follow-set-ambiguity-restrictions">Follow-set Ambiguity Restrictions</a></h2>
<h2><a class="header" href="#随集歧义限制译者注该节还需要继续校对打磨主要难点还是因为附录的宏定义规范译者还没有能全部搞懂" id="随集歧义限制译者注该节还需要继续校对打磨主要难点还是因为附录的宏定义规范译者还没有能全部搞懂">随集歧义限制（译者注：该节还需要继续校对打磨，主要难点还是因为附录的宏定义规范译者还没有能全部搞懂）</a></h2>
<p>宏系统使用的解析器相当强大，但是为了防止其在 Rust 的当前或未来版本中出现二义性解析，因此对它做出了限制。特别地，在消除二义性展开的基本规则之外又增加了一条：元变量匹配的非终结符(nonterminal)必须后跟一个已经确定为可以用来安全分隔匹配段的分隔符。</p>
<p>例如，像 <code>$i:expr [ , ]</code> 这样的宏匹配器在现今的 Rust 中理论上是可以接受的，因为现在 <code>[,]</code> 不可能是合法表达式的一部分，因此解析始终是明确的。但是，由于 <code>[</code> 可以开始一个尾随表达式(trailing expressions)，因此 <code>[</code> 不是一个可以安全排除在表达式后面出现的字符。如果在接下来的 Rust 版本中接受了 <code>[,]</code>，那么这个匹配器就会产生歧义或是错误解析，破坏正常代码。但是，像<code>$i:expr,</code> 或 <code>$i:expr;</code> 这样的匹配符始终是合法的，因为 <code>,</code> 和<code>;</code> 是合法的表达式分隔符。目前规范中的规则是：（译者注：下面的规则不是绝对的，因为宏的基础理论还在发展中。）</p>
<ul>
<li>
<p><code>expr</code> 和 <code>stmt</code> 只能后跟一个： <code>=&gt;</code>、<code>,</code>、<code>;</code>。</p>
</li>
<li>
<p><code>pat</code> 和 <code>pat_param</code> 只能后跟一个： <code>=&gt;</code>、<code>,</code>、<code>=</code>、<code>|</code>、<code>if</code>、<code>in</code>。</p>
</li>
<li>
<p><code>path</code> 和 <code>ty</code> 只能后跟一个： <code>=&gt;</code>、<code>,</code>、<code>=</code>、<code>|</code>、<code>;</code>、<code>:</code>、<code>&gt;</code>、<code>&gt;&gt;</code>、<code>[</code>、<code>{</code>、<code>as</code>、<code>where</code>、块(<code>block</code>)型非终结符(block nonterminals)。</p>
</li>
<li>
<p><code>vis</code> 只能后跟一个：<code>,</code>、非原生字符串 <code>priv</code> 以外的任何标识符和关键字、可以表示类型开始的任何 token、<code>ident</code>或<code>ty</code>或<code>path</code>型非终结符。</p>
<p>（译者注：可以表示类型开始的 token 有：{<code>(</code>, <code>[</code>, <code>!</code>, <code>\*</code>,<code>&amp;</code>, <code>&amp;&amp;</code>, <code>?</code>, 生存期, <code>&gt;</code>, <code>&gt;&gt;</code>, <code>::</code>, 非关键字标识符, <code>super</code>,<code>self</code>, <code>Self</code>, <code>extern</code>, <code>crate</code>, <code>$crate</code>, <code>_</code>, <code>for</code>, <code>impl</code>, <code>fn</code>, <code>unsafe</code>,<code>typeof</code>, <code>dyn</code>}。注意这个列表也不一定全。）</p>
</li>
<li>
<p>其它所有的匹配段选择器没有限制。</p>
</li>
</ul>
<p>当涉及到重复元时，随集歧义限制适用于所有可能的展开次数，注意需将重复元中的分隔符考虑在内。这意味着：</p>
<ul>
<li>如果重复元包含分隔符，则分隔符必须能够跟随重复元的内容重复。</li>
<li>如果重复元可以重复多次（<code>*</code> 或 <code>+</code>），那么重复元的内容必须能自我重复。</li>
<li>重复元前后内容必须严格匹配匹配器中指定的前后内容。</li>
<li>如果重复元可以匹配零次（<code>*</code> 或 <code>?</code>），那么它后面的内容必须能够直接跟在它前面的内容后面。</li>
</ul>
<p>有关更多详细信息，请参阅[正式规范]。</p>
<h2><a class="header" href="#procedural-macros" id="procedural-macros">Procedural Macros</a></h2>
<h2><a class="header" href="#过程宏" id="过程宏">过程宏</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/procedural-macros.md">procedural-macros.md</a><br />
commit: a1ef5a09c0281b0f2a65c18670e927ead61eb1b2 <br />
本章译文最后维护日期：2020-11-6</p>
</blockquote>
<p><em>过程宏</em>允许在执行函数时创建句法扩展。过程宏有三种形式:</p>
<ul>
<li><a href="procedural-macros.html#function-like-procedural-macros">类函数宏(function-like macros)</a> - <code>custom!(...)</code></li>
<li><a href="procedural-macros.html#derive-macros">派生宏(derive macros)</a>- <code>#[derive(CustomDerive)]</code></li>
<li><a href="procedural-macros.html#attribute-macros">属性宏(attribute macros)</a> - <code>#[CustomAttribute]</code></li>
</ul>
<p>过程宏允许在编译时运行对 Rust 句法进行操作的代码，它可以在消费掉一些 Rust 句法输入的同时产生新的 Rust 句法输出。可以将过程宏想象成是从一个 <abbr title="抽象句法树：Abstract Syntax Tree">AST</abbr> 到另一个 <abbr title="抽象句法树：Abstract Syntax Tree">AST</abbr> 的函数映射。</p>
<p>过程宏必须在 <a href="linkage.html">crate 类型</a>为 <code>proc-macro</code> 的 crate 中定义。</p>
<blockquote>
<p><strong>注意</strong>: 使用 Cargo 时，定义过程宏的 crate 的配置文件里要使用 <code>proc-macro</code>键做如下设置：</p>
<pre><code class="language-toml">[lib]
proc-macro = true
</code></pre>
</blockquote>
<p>作为函数，它们要么有返回句法，要么触发 panic，要么永无休止地循环。返回句法根据过程宏的类型替换或添加句法；panic 会被编译器捕获，并将其转化为编译器错误；无限循环不会被编译器不会捕获，但会导致编译器被挂起。</p>
<p>过程宏在编译时运行，因此具有与编译器相同的环境资源。例如，它可以访问的标准输入、标准输出和标准错误输出等，这些编译器可以访问的资源。类似地，文件访问也是一样的。因此，过程宏与 <a href="https://doc.rust-lang.org/cargo/reference/build-scripts.html">Cargo构建脚本</a> 具有相同的安全考量。</p>
<p>过程宏有两种报告错误的方法。首先是 panic；第二个是发布 <a href="https://doc.rust-lang.org/std/macro.compile_error.html"><code>compile_error</code></a> 性质的宏调用。</p>
<h3><a class="header" href="#the-proc_macro-crate" id="the-proc_macro-crate">The <code>proc_macro</code> crate</a></h3>
<p>过程宏类型的 crate 几乎总是会去链接编译器提供的 <a href="https://doc.rust-lang.org/proc_macro/index.html"><code>proc_macro</code> crate</a>。<code>proc_macro</code> crate 提供了编写过程宏所需的各种类型和工具来让编写更容易。</p>
<p>此 crate 主要包含了一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 类型。过程宏其实是在 *token流(token streams)*上操作，而不是在某个或某些 AST 节点上操作，因为这对于编译器和过程宏的编译目标来说，这是一个随着时间推移要稳定得多的接口。<em>token流</em>大致相当于 <code>Vec&lt;TokenTree&gt;</code>，其中 <code>TokenTree</code> 可以大致视为词法 token。例如，<code>foo</code> 是标识符(<code>Ident</code>)类型的 token，<code>.</code> 是一个标点符号(<code>Punct</code>)类型的 token，<code>1.2</code> 是一个字面量(<code>Literal</code>)类型的 token。不同于 <code>Vec&lt;TokenTree&gt;</code> 的是 <code>TokenStream</code> 的克隆成本很低。</p>
<p>所有类型的 token 都有一个与之关联的 <code>Span</code>。<code>Span</code> 是一个不透明的值，不能被修改，但可以被制造。<code>Span</code> 表示程序内的源代码范围，主要用于错误报告。可以事先（通过函数 <code>set_span</code>）配置任何 token 的 <code>Span</code>。</p>
<h3><a class="header" href="#procedural-macro-hygiene" id="procedural-macro-hygiene">Procedural macro hygiene</a></h3>
<h3><a class="header" href="#过程宏的卫生性" id="过程宏的卫生性">过程宏的卫生性</a></h3>
<p>过程宏是<em>非卫生的(unhygienic)</em>。这意味着它的行为就好像它输出的 token流是被简单地内联写入它周围的代码中一样。这意味着它会受到外部程序项的影响，也会影响外部导入。</p>
<p>鉴于此限制，宏作者需要小心地确保他们的宏能在尽可能多的上下文中正常工作。这通常包括对库中程序项使用绝对路径(例如，使用 <code>::std::option::Option</code> 而不是 <code>Option</code>)，或者确保生成的函数具有不太可能与其他函数冲突的名称（如 <code>__internal_foo</code>，而不是 <code>foo</code>）。</p>
<h3><a class="header" href="#function-like-procedural-macros" id="function-like-procedural-macros">Function-like procedural macros</a></h3>
<h3><a class="header" href="#类函数过程宏" id="类函数过程宏">类函数过程宏</a></h3>
<p><em>类函数过程宏</em>是使用宏调用运算符（<code>!</code>）调用的过程宏。</p>
<p>这种宏是由一个带有 <code>proc_macro</code><a href="attributes.html">属性</a>和 <code>(TokenStream) -&gt; TokenStream</code>签名的 <a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是由宏调用的定界符界定的内容，输出 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 将替换整个宏调用。</p>
<p>例如，下面的宏定义忽略它的输入，并将函数 <code>answer</code> 输出到它的作用域。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span>extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn make_answer(_item: TokenStream) -&gt; TokenStream {
    &quot;fn answer() -&gt; u32 { 42 }&quot;.parse().unwrap()
}
</code></pre>
<p>然后我们用它在一个二进制 crate 里打印 “42” 到标准输出。</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">extern crate proc_macro_examples;
use proc_macro_examples::make_answer;

make_answer!();

fn main() {
    println!(&quot;{}&quot;, answer());
}
</code></pre>
<p>类函数过程宏可以在任何宏调用位置调用，这些位置包括<a href="statements.html">语句</a>、<a href="expressions.html">表达式</a>、<a href="patterns.html">模式</a>、<a href="types.html#type-expressions">类型表达式</a>、<a href="items.html">程序项</a>可以出现的位置（包括<a href="items/external-blocks.html"><code>extern</code>块</a>里、固有(inherent)<a href="items/implementations.html">实现</a>里和 trait实现里、以及 <a href="items/traits.html">trait声明</a>里）。</p>
<h3><a class="header" href="#derive-macros" id="derive-macros">Derive macros</a></h3>
<h3><a class="header" href="#派生宏" id="派生宏">派生宏</a></h3>
<p><em>派生宏</em>为<a href="attributes/derive.html">派生(<code>derive</code>)属性</a>定义新输入。这类宏在给定输入<a href="items/structs.html">结构体(<code>struct</code>)</a>、<a href="items/enumerations.html">枚举(<code>enum</code>)</a>或<a href="items/unions.html">联合体(<code>union</code>)</a> token流的情况下创建新<a href="items.html">程序项</a>。它们也可以定义<a href="procedural-macros.html#derive-macro-helper-attributes">派生宏辅助属性</a>。</p>
<p>自定义派生宏由带有 <code>proc_macro_derive</code>属性和 <code>(TokenStream) -&gt; TokenStream</code>签名的<a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。</p>
<p>输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是带有 <code>derive</code> 属性的程序项的 token流。输出 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 必须是一组程序项，然后将这组程序项追加到输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 中的那条程序项所在的<a href="items/modules.html">模块</a>或<a href="expressions/block-expr.html">块</a>中。</p>
<p>下面是派生宏的一个示例。它没有对输入执行任何有用的操作，只是追加了一个函数 <code>answer</code>。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span>extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_derive(AnswerFn)]
pub fn derive_answer_fn(_item: TokenStream) -&gt; TokenStream {
    &quot;fn answer() -&gt; u32 { 42 }&quot;.parse().unwrap()
}
</code></pre>
<p>然后使用这个派生宏：</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">extern crate proc_macro_examples;
use proc_macro_examples::AnswerFn;

#[derive(AnswerFn)]
struct Struct;

fn main() {
    assert_eq!(42, answer());
}
</code></pre>
<h4><a class="header" href="#derive-macro-helper-attributes" id="derive-macro-helper-attributes">Derive macro helper attributes</a></h4>
<h4><a class="header" href="#派生宏辅助属性" id="派生宏辅助属性">派生宏辅助属性</a></h4>
<p>派生宏可以将额外的<a href="attributes.html">属性</a>添加到它们所在的<a href="items.html">程序项</a>的作用域中。这些属性被称为<em>派生宏辅助属性</em>。这些属性是<a href="attributes.html#active-and-inert-attributes">惰性的</a>，它们存在的唯一目的是将这些属性在使用现场获得的属性值反向输入到定义它们的派生宏中。也就是说所有该宏的宏应用都可以看到它们。</p>
<p>定义辅助属性的方法是在 <code>proc_macro_derive</code> 宏中放置一个 <code>attributes</code> 键，此键带有一个使用逗号分隔的标识符列表，这些标识符是辅助属性的名称。</p>
<p>例如，下面的派生宏定义了一个辅助属性 <code>helper</code>，但最终没有用它做任何事情。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type=&quot;proc-macro&quot;]
</span><span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_derive(HelperAttr, attributes(helper))]
pub fn derive_helper_attr(_item: TokenStream) -&gt; TokenStream {
    TokenStream::new()
}
</code></pre>
<p>然后在一个结构体上使用这个派生宏：</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">#[derive(HelperAttr)]
struct Struct {
    #[helper] field: ()
}
</code></pre>
<h3><a class="header" href="#attribute-macros" id="attribute-macros">Attribute macros</a></h3>
<h3><a class="header" href="#属性宏" id="属性宏">属性宏</a></h3>
<p><em>属性宏</em>定义可以附加到<a href="items.html">程序项</a>上的新的<a href="attributes.html">外部属性</a>，这些程序项包括<a href="items/external-blocks.html">外部(<code>extern</code>)块</a>、固有<a href="items/implementations.html">实现</a>、trate实现，以及 <a href="items/traits.html">trait声明</a>中的各类程序项。</p>
<p>属性宏由带有 <code>proc_macro_attribute</code><a href="attributes.html">属性</a>和 <code>(TokenStream, TokenStream) -&gt; TokenStream</code>签名的<a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。签名中的第一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是属性名称后面的定界 token树(delimited token tree)（不包括外层定界符）。如果该属性作为裸属性(bare attribute)给出，则第一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 值为空。第二个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是<a href="items.html">程序项</a>的其余部分，包括该程序项的其他<a href="attributes.html">属性</a>。输出的 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 将此属性宏应用的<a href="items.html">程序项</a>替换为任意数量的程序项。</p>
<p>例如，下面这个属性宏接受输入流并按原样返回，实际上对属性并无操作。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span><span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_attribute]
pub fn return_as_is(_attr: TokenStream, item: TokenStream) -&gt; TokenStream {
    item
}
</code></pre>
<p>下面示例显示了属性宏看到的字符串化的 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a>。输出将显示在编译时的编译器输出窗口中。（具体格式是以 &quot;out:&quot;为前缀的）输出内容也都在后面每个示例函数后面的注释中给出了。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore">// my-macro/src/lib.rs
<span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_attribute]
pub fn show_streams(attr: TokenStream, item: TokenStream) -&gt; TokenStream {
    println!(&quot;attr: \&quot;{}\&quot;&quot;, attr.to_string());
    println!(&quot;item: \&quot;{}\&quot;&quot;, item.to_string());
    item
}
</code></pre>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">// src/lib.rs
extern crate my_macro;

use my_macro::show_streams;

// 示例: 基础函数
#[show_streams]
fn invoke1() {}
// out: attr: &quot;&quot;
// out: item: &quot;fn invoke1() { }&quot;

// 示例: 带输入参数的属性
#[show_streams(bar)]
fn invoke2() {}
// out: attr: &quot;bar&quot;
// out: item: &quot;fn invoke2() {}&quot;

// 示例: 输入参数中有多个 token 的
#[show_streams(multiple =&gt; tokens)]
fn invoke3() {}
// out: attr: &quot;multiple =&gt; tokens&quot;
// out: item: &quot;fn invoke3() {}&quot;

// 示例:
#[show_streams { delimiters }]
fn invoke4() {}
// out: attr: &quot;delimiters&quot;
// out: item: &quot;fn invoke4() {}&quot;
</code></pre>
<!-- 2020-11-12-->
<!-- checked --><h1><a class="header" href="#crate-和源文件" id="crate-和源文件">crate 和源文件</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/crates-and-source-files.md">crates-and-source-files.md</a><br />
commit: eabdf09207bf3563ae96db9d576de0758c413d5d <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Crate</em> :<br />
   UTF8BOM<sup>?</sup><br />
   SHEBANG<sup>?</sup><br />
   <a href="attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
   <a href="items.html"><em>Item</em></a><sup>*</sup></p>
</blockquote>
<blockquote>
<p><strong><sup>词法</sup></strong><br />
UTF8BOM : <code>\uFEFF</code><br />
SHEBANG : <code>#!</code> ~<code>\n</code><sup>+</sup><a href="crates-and-source-files.html#shebang">†</a></p>
</blockquote>
<blockquote>
<p>注意：尽管像任何其他语言一样，Rust 也都可以通过解释器和编译器实现，但现在唯一存在的实现是编译器，并且该语言也是一直被设计为可编译的。因为这些原因，所以本章节所有的讨论都是基于编译器这条路径的。</p>
</blockquote>
<p>Rust 的语义有编译时和运行时之间的<em>阶段差异(phase distinction)</em>。<sup class="footnote-reference"><a href="#phase-distinction">1</a></sup> 其中<em>静态解释</em>的语义规则控制编译的成败，而<em>动态解释</em>的语义规则控制程序在运行时的行为。</p>
<p>编译模型以 <em>crate</em> 为中心。每次编译都以源码的形式处理单个的 crate，如果成功，将生成二进制形式的单个 crate：可执行文件或某种类型的库文件。<sup class="footnote-reference"><a href="#cratesourcefile">2</a></sup></p>
<p>crate 是编译和链接的单元，也是版本控制、版本分发和运行时加载的基本单元。一个 crate 包含一个嵌套的带作用域的<a href="items/modules.html">模块</a><em>树</em>。这个树的顶层是一个匿名的模块（从模块内部路径的角度来看），并且一个 crate 中的任何程序项都有一个规范的<a href="paths.html">模块路径</a>来表示它在 crate 的模块树中的位置。</p>
<p>Rust 编译器总是使用单个源文件作为输入来开启编译过程的，并且总是生成单个输出 crate。对输入源文件的处理可能导致其他源文件作为模块被加载进来。源文件的扩展名为 <code>.rs</code>。</p>
<p>Rust 源文件描述了一个模块，其名称和（在当前 crate 的模块树中的）位置是从源文件外部定义的：要么通过引用源文件中的显式<a href="items/modules.html">模块(<em>Module</em>)</a>项，要么由 crate 本身的名称定义。每个源文件都是一个模块，但并非每个模块都需要自己的源文件：多个<a href="items/modules.html">模块定义</a>可以嵌套在同一个文件中。</p>
<p>每个源文件包含一个由零个或多个<a href="items.html">程序项</a>定义组成的代码序列，并且这些源文件都可选地从应用于其内部模块的任意数量的<a href="attributes.html">属性</a>开始，大部分这些属性都会会影响编译器行为。匿名的 crate 根模块可附带一些应用于整个 crate 的属性。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 指定 crate 名称.
#![crate_name = &quot;projx&quot;]

// 指定编译输出文件的类型
#![crate_type = &quot;lib&quot;]

// 打开一种警告
// 这句可以放在任何模块中, 而不是只能放在匿名 crate 模块里。
#![warn(non_camel_case_types)]
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#byte-order-mark" id="byte-order-mark">Byte order mark</a></h2>
<h2><a class="header" href="#字节顺序标记bom" id="字节顺序标记bom">字节顺序标记(BOM)</a></h2>
<p>可选的<a href="https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8"><em>UTF8字节序标记</em></a>（UTF8BOM产生式）表示该文件是用 UTF8 编码的。它只能出现在文件的开头，并且编译器会忽略它。</p>
<h2><a class="header" href="#shebang" id="shebang">Shebang</a></h2>
<p>源文件可以有一个<a href="https://en.wikipedia.org/wiki/Shebang_(Unix)"><em>shebang</em></a>（SHEBANG产生式），它指示操作系统使用什么程序来执行此文件。它本质上是将源文件作为可执行脚本处理。shebang 只能出现在文件的开头（但是要在可选的 <em>UTF8BOM</em> 生产式之后）。它会被编译器忽略。例如：</p>
<!-- ignore: tests don't like shebang -->
<pre><code class="language-rust ignore">#!/usr/bin/env rustx

fn main() {
    println!(&quot;Hello!&quot;);
}
</code></pre>
<p>为了避免与<a href="attributes.html">属性</a>混淆， Rust 对 shebang 句法做了一个限制：是 <code>#!</code> 字符不能后跟 token <code>[</code>，忽略中间的<a href="comments.html">注释</a>或<a href="whitespace.html">空白符</a>。如果违反此限制，则不会将其视为 shebang，而会将其视为属性的开始。</p>
<h2><a class="header" href="#preludes-and-no_std" id="preludes-and-no_std">Preludes and <code>no_std</code></a></h2>
<h2><a class="header" href="#预导入包和-no_std" id="预导入包和-no_std">预导入包和 <code>no_std</code></a></h2>
<p>本节内容已经移入<a href="names/preludes.html">预导入包那章里</a>了。</p>
<!-- 本节是为了让其他资料的链入链接不止于立即失效，一旦其他链接被更新，本节就会删除 -->
<h2><a class="header" href="#main-functions" id="main-functions">Main Functions</a></h2>
<h2><a class="header" href="#main函数" id="main函数">main函数</a></h2>
<p>包含 <code>main</code><a href="items/functions.html">函数</a>的 crate 可以被编译成可执行文件。如果一个 <code>main</code>函数存在，它必须不能有参数，不能对其声明任何 <a href="trait-bounds.html">trait约束或生存期约束</a>，不能有任何 <a href="items/generics.html#where-clauses">where子句</a>，并且它的返回类型必须是以下类型之一:</p>
<ul>
<li><code>()</code></li>
<li><code>Result&lt;(), E&gt; where E: Error</code></li>
</ul>
<!-- * `!` -->
<!-- * Result<!, E> where E: Error` -->
<blockquote>
<p>注意: 允许哪些返回类型的实现是由暂未稳定的 <a href="https://doc.rust-lang.org/std/process/trait.Termination.html"><code>Termination</code></a> trait 决定的。</p>
</blockquote>
<!-- 如果前面这节需要更新 (从 "必须不能有参数" 开始, 同时需要修改 attributes/testing.md 文件 -->
<h3><a class="header" href="#the-no_main-attribute" id="the-no_main-attribute">The <code>no_main</code> attribute</a></h3>
<h3><a class="header" href="#no_main属性" id="no_main属性"><code>no_main</code>属性</a></h3>
<p>可在 crate 层级使用 *<code>no_main</code><a href="attributes.html">属性</a>*来禁止对可执行二进制文件发布 <code>main</code> symbol，即禁止当前 crate 的 main 函数的执行。当链接的其他对象定义了 <code>main</code>函数时，这很有用。</p>
<h2><a class="header" href="#the-crate_name-attribute" id="the-crate_name-attribute">The <code>crate_name</code> attribute</a></h2>
<h2><a class="header" href="#crate_name属性" id="crate_name属性"><code>crate_name</code>属性</a></h2>
<p>可在 crate 层级应用 <em><code>crate_name</code><a href="attributes.html">属性</a></em>，并通过使用 <a href="attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法来指定 crate 的名称。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span>#![crate_name = &quot;mycrate&quot;]
<span class="boring">fn main() {
</span><span class="boring">}
</span></code></pre></pre>
<p>crate 名称不能为空，且只能包含 [Unicode字母数字]或字符 <code>-</code>(U+002D)。</p>
<div class="footnote-definition" id="phase-distinction"><sup class="footnote-definition-label">1</sup>
<p>这种区别也存在于解释器中。静态检查，如语法分析、类型检查和 lint检查，都应该在程序执行之前进行，而不要去管程序何时执行。</p>
</div>
<div class="footnote-definition" id="cratesourcefile"><sup class="footnote-definition-label">2</sup>
<p>crate 有点类似于 ECMA-335 CLI 模型中的 <em>assembly</em>、SML/NJ 编译管理器中的 <em>library</em>、Owens 和 Flatt 模块系统中的 <em>unit</em>， 或 Mesa 中的 <em>configuration</em>。</p>
</div>
<script>
(function() {
    var fragments = {
        "#preludes-and-no_std": "names/preludes.html",
    };
    var target = fragments[window.location.hash];
    if (target) {
        var url = window.location.toString();
        var base = url.substring(0, url.lastIndexOf('/'));
        window.location.replace(base + "/" + target);
    }
})();
</script>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#conditional-compilation" id="conditional-compilation">Conditional compilation</a></h1>
<h1><a class="header" href="#条件编译" id="条件编译">条件编译</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/conditional-compilation.md">conditional-compilation.md</a><br />
commit: 949726950a4ac5c8674e902dc33c09b48fc7434c <br />
本章译文最后维护日期：2021-5-6</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ConfigurationPredicate</em> :<br />
      <em>ConfigurationOption</em><br />
   | <em>ConfigurationAll</em><br />
   | <em>ConfigurationAny</em><br />
   | <em>ConfigurationNot</em></p>
<p><em>ConfigurationOption</em> :<br />
   <a href="identifiers.html">IDENTIFIER</a> (<code>=</code> (<a href="tokens.html#string-literals">STRING_LITERAL</a> | <a href="tokens.html#raw-string-literals">RAW_STRING_LITERAL</a>))<sup>?</sup></p>
<p><em>ConfigurationAll</em><br />
   <code>all</code> <code>(</code> <em>ConfigurationPredicateList</em><sup>?</sup> <code>)</code></p>
<p><em>ConfigurationAny</em><br />
   <code>any</code> <code>(</code> <em>ConfigurationPredicateList</em><sup>?</sup> <code>)</code></p>
<p><em>ConfigurationNot</em><br />
   <code>not</code> <code>(</code> <em>ConfigurationPredicate</em> <code>)</code></p>
<p><em>ConfigurationPredicateList</em><br />
   <em>ConfigurationPredicate</em> (<code>,</code> <em>ConfigurationPredicate</em>)<sup>*</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p>根据某些条件，<!-- 这个定义有点空洞 --> *条件性编译的源代码(Conditionally compiled source code)*可以被认为是 crate 源代码的一部分，也可以不被认为是 crate 源代码的一部分。可以使用<a href="attributes.html">属性</a> <a href="conditional-compilation.html#the-cfg-attribute"><code>cfg</code></a> 和 <a href="conditional-compilation.html#the-cfg_attr-attribute"><code>cfg_attr</code></a> 以及内置的 <a href="conditional-compilation.html#the-cfg-macro"><code>cfg</code> macro</a> 来有条件地对源代码进行编译。这些条件可以基于被编译的 crate 的目标架构、传递给编译器的值，以及下面将详细描述的一些其他事项。</p>
<p>每种形式的编译条件都有一个计算结果为真或假的<em>配置谓词(configuration predicate)</em>。谓词是以下内容之一：</p>
<ul>
<li>一个配置选项。如果设置了该选项，则为真，如果未设置则为假。</li>
<li><code>all()</code> 这样的配置谓词列表，列表内的配置谓词以逗号分隔。如果至少有一个谓词为假，则为假。如果没有谓词，则为真。</li>
<li><code>any()</code> 这样的配置谓词列表，列表内的配置谓词以逗号分隔。如果至少有一个谓词为真，则为真。如果没有谓词，则为假。</li>
<li>带一个配置谓词的 <code>not()</code> 模式 。如果此谓词为假，整个配置它为真；如果此谓词为真，整个配置为假。</li>
</ul>
<p><em>配置选项</em>可以是名称，也可以是键值对，它们可以设置，也可以不设置。名称以单个标识符形式写入，例如 <code>unix</code>。键值对被写为标识符后跟 <code>=</code>，然后再跟一个字符串。例如，<code>target_arch=“x86_64”</code> 就是一个配置选项。</p>
<blockquote>
<p><strong>注意</strong>: <code>=</code> 周围的空白符将被忽略。<code>foo=&quot;bar&quot;</code> 和 <code>foo = &quot;bar&quot;</code> 是等价的配置选项。</p>
</blockquote>
<p>键在键值对配置选项列表中不是唯一的。例如，<code>feature = &quot;std&quot;</code> and <code>feature = &quot;serde&quot;</code> 可以同时设置。</p>
<h2><a class="header" href="#set-configuration-options" id="set-configuration-options">Set Configuration Options</a></h2>
<h2><a class="header" href="#设置配置选项" id="设置配置选项">设置配置选项</a></h2>
<p>设置哪些配置选项是在 crate 编译期时就静态确定的。一些选项属于<em>编译器设置集(compiler-set)</em>，这部分选项是编译器根据相关编译数据设置的。其他选项属于<em>任意设置集(arbitrarily-set)</em>，这部分设置必须从代码之外传参给编译器来自主设置。无法在正在编译的 crate 的源代码中设置编译配置选项。</p>
<blockquote>
<p><strong>注意</strong>: 对于 <code>rustc</code>，任意配置集的配置选项要使用命令行参数 <a href="https://doc.rust-lang.org/rustc/command-line-arguments.html#--cfg-configure-the-compilation-environment"><code>--cfg</code></a> 来设置。</p>
</blockquote>
<blockquote>
<p><strong>注意</strong>: 键名为 <code>feature</code> 的配置选项一般被 <a href="https://doc.rust-lang.org/cargo/reference/features.html">Cargo</a> 约定用于指定编译期（用到的各种编译）选项和可选依赖项。</p>
</blockquote>
<div class="warning">
<p>警告：任意配置集的配置选项可能与编译器设置集的配置选项设置相同的值。例如，在编译一个 Windows 目标时，可以执行命令行 <code>rustc --cfg &quot;unix&quot; program.rs</code>，这样就同时设置了 <code>unix</code> 和 <code>windows</code> 配置选项。但实际上这样做是不明智的。</p>
</div>
<h3><a class="header" href="#target_arch" id="target_arch"><code>target_arch</code></a></h3>
<p>键值对选项，用于一次性设置编译目标的 CPU 架构。该值类似于平台的目标三元组(target triple)<sup class="footnote-reference"><a href="#target-triple">1</a></sup>中的第一个元素，但也不完全相同。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;x86&quot;</code></li>
<li><code>&quot;x86_64&quot;</code></li>
<li><code>&quot;mips&quot;</code></li>
<li><code>&quot;powerpc&quot;</code></li>
<li><code>&quot;powerpc64&quot;</code></li>
<li><code>&quot;arm&quot;</code></li>
<li><code>&quot;aarch64&quot;</code></li>
</ul>
<h3><a class="header" href="#target_feature" id="target_feature"><code>target_feature</code></a></h3>
<p>键值对选项，用于设置当前编译目标的可用平台特性。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;avx&quot;</code></li>
<li><code>&quot;avx2&quot;</code></li>
<li><code>&quot;crt-static&quot;</code></li>
<li><code>&quot;rdrand&quot;</code></li>
<li><code>&quot;sse&quot;</code></li>
<li><code>&quot;sse2&quot;</code></li>
<li><code>&quot;sse4.1&quot;</code></li>
</ul>
<p>有关可用特性的更多细节，请参见 <a href="attributes/codegen.html#the-target_feature-attribute"><code>target_feature</code>属性</a>。此外，编译器还为 <code>target_feature</code>选项提供了一个额外的 <code>crt-static</code>特性，它表示需要链接一个可用的<a href="linkage.html#static-and-dynamic-c-runtimes">静态C运行时</a>。</p>
<h3><a class="header" href="#target_os" id="target_os"><code>target_os</code></a></h3>
<p>键值对选项，用于一次性设置编译目标的操作系统类型。该值类似于平台目标三元组中的第二和第三个元素。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;windows&quot;</code></li>
<li><code>&quot;macos&quot;</code></li>
<li><code>&quot;ios&quot;</code></li>
<li><code>&quot;linux&quot;</code></li>
<li><code>&quot;android&quot;</code></li>
<li><code>&quot;freebsd&quot;</code></li>
<li><code>&quot;dragonfly&quot;</code></li>
<li><code>&quot;openbsd&quot;</code></li>
<li><code>&quot;netbsd&quot;</code></li>
</ul>
<h3><a class="header" href="#target_family" id="target_family"><code>target_family</code></a></h3>
<p>键值对选项提供了对具体目标平台更通用化的描述，比如编译目标操作系统或架构。可以设置任意数量的键值对。
最多设置一次，用于设置编译目标的操作系统类别。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;unix&quot;</code></li>
<li><code>&quot;windows&quot;</code></li>
<li><code>&quot;wasm&quot;</code></li>
</ul>
<h3><a class="header" href="#unix-and-windows" id="unix-and-windows"><code>unix</code> and <code>windows</code></a></h3>
<h3><a class="header" href="#unix-和-windows" id="unix-和-windows"><code>unix</code> 和 <code>windows</code></a></h3>
<p>如果设置了 <code>target_family = &quot;unix&quot;</code> 则谓词 <code>unix</code> 为真；如果设置了 <code>target_family = &quot;windows&quot;</code> 则谓词 <code>windows</code> 为真。</p>
<h3><a class="header" href="#target_env" id="target_env"><code>target_env</code></a></h3>
<p>键值对选项，用来进一步消除编译目标平台信息与所用 ABI 或 <code>libc</code> 相关的歧义。由于历史原因，仅当实际需要消除歧义时，才将此值定义为非空字符串。因此，例如在许多 GNU 平台上，此值将为空。该值类似于平台目标三元组的第四个元素，但也有区别。一个区别是在嵌入式 ABI 上，比如在目标为嵌入式系统时，<code>gnueabihf</code> 会简单地将 <code>target_env</code> 定义为 <code>&quot;gnu&quot;</code>。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;&quot;</code></li>
<li><code>&quot;gnu&quot;</code></li>
<li><code>&quot;msvc&quot;</code></li>
<li><code>&quot;musl&quot;</code></li>
<li><code>&quot;sgx&quot;</code></li>
</ul>
<h3><a class="header" href="#target_endian" id="target_endian"><code>target_endian</code></a></h3>
<p>键值对选项，根据编译目标的 CPU 的字节序(endianness)属性一次性设置值为 “little” 或 “big”。</p>
<h3><a class="header" href="#target_pointer_width" id="target_pointer_width"><code>target_pointer_width</code></a></h3>
<p>键值对选项，用于一次性设置编译目标的指针位宽(pointer width in bits)。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;16&quot;</code></li>
<li><code>&quot;32&quot;</code></li>
<li><code>&quot;64&quot;</code></li>
</ul>
<h3><a class="header" href="#target_vendor" id="target_vendor"><code>target_vendor</code></a></h3>
<p>键值对选项，用于一次性设置编译目标的供应商。</p>
<p>示例值：</p>
<ul>
<li><code>&quot;apple&quot;</code></li>
<li><code>&quot;fortanix&quot;</code></li>
<li><code>&quot;pc&quot;</code></li>
<li><code>&quot;unknown&quot;</code></li>
</ul>
<h3><a class="header" href="#test" id="test"><code>test</code></a></h3>
<p>在编译测试套件时启用。通过在 <code>rustc</code> 里使用 <a href="https://doc.rust-lang.org/rustc/command-line-arguments.html#--test-build-a-test-harness"><code>--test</code></a> 命令行参数来完成此启用。请参阅<a href="attributes/testing.html">测试</a>章节来获取更多和测试支持相关的信息。</p>
<h3><a class="header" href="#debug_assertions" id="debug_assertions"><code>debug_assertions</code></a></h3>
<p>在进行非优化编译时默认启用。这可以用于在开发中启用额外的代码调试功能，但不能在生产中启用。例如，它控制着标准库的 <a href="https://doc.rust-lang.org/std/macro.debug_assert.html"><code>debug_assert!</code></a>宏（是否可用）。</p>
<h3><a class="header" href="#proc_macro" id="proc_macro"><code>proc_macro</code></a></h3>
<p>当须要指定当前 crate 的<a href="linkage.html">编译输出文件类型(crate-type)</a>为 <code>proc_macro</code> 时设置。</p>
<h2><a class="header" href="#forms-of-conditional-compilation" id="forms-of-conditional-compilation">Forms of conditional compilation</a></h2>
<h2><a class="header" href="#条件编译的形式" id="条件编译的形式">条件编译的形式</a></h2>
<h3><a class="header" href="#the-cfg-attribute" id="the-cfg-attribute">The <code>cfg</code> attribute</a></h3>
<h3><a class="header" href="#cfg属性" id="cfg属性"><code>cfg</code>属性</a></h3>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>CfgAttrAttribute</em> :<br />
   <code>cfg</code> <code>(</code> <em>ConfigurationPredicate</em> <code>)</code></p>
</blockquote>
<!-- 这里可以用“激活属性”来称呼吗？should we say they're active attributes here? -->
<p><code>cfg</code><a href="attributes.html">属性</a>根据配置谓词有条件地包括它所附加的东西。</p>
<p>它被写成 <code>cfg</code> 后跟一个 <code>(</code>，再跟一个配置谓词，最后是一个 <code>)</code>。</p>
<p>如果谓词为真，则重写该部分代码，使其上没有 <code>cfg</code> 属性。如果谓词为假，则从源代码中删除该内容。</p>
<p>在函数上的一些例子:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 该函数只会在编译目标为 macOS 时才会包含在构建中
#[cfg(target_os = &quot;macos&quot;)]
fn macos_only() {
  // ...
}

// 此函数仅在定义了 foo 或 bar 时才会被包含在构建中
#[cfg(any(foo, bar))]
fn needs_foo_or_bar() {
  // ...
}

// 此函数仅在编译目标是32位体系架构的类unix 系统时才会被包含在构建中
#[cfg(all(unix, target_pointer_width = &quot;32&quot;))]
fn on_32bit_unix() {
  // ...
}

// 此函数仅在没有定义 foo 时才会被包含在构建中
#[cfg(not(foo))]
fn needs_not_foo() {
  // ...
}
<span class="boring">}
</span></code></pre></pre>
<p><code>cfg</code>属性允许在任何允许属性的地方上使用。</p>
<h3><a class="header" href="#the-cfg_attr-attribute" id="the-cfg_attr-attribute">The <code>cfg_attr</code> attribute</a></h3>
<h3><a class="header" href="#cfg_attr属性" id="cfg_attr属性"><code>cfg_attr</code>属性</a></h3>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>CfgAttrAttribute</em> :<br />
   <code>cfg_attr</code> <code>(</code> <em>ConfigurationPredicate</em> <code>,</code> <em>CfgAttrs</em><sup>?</sup> <code>)</code></p>
<p><em>CfgAttrs</em> :<br />
   <a href="attributes.html"><em>Attr</em></a> (<code>,</code> <a href="attributes.html"><em>Attr</em></a>)<sup>*</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p><code>cfg_attr</code><a href="attributes.html">属性</a>根据配置谓词有条件地包含<a href="attributes.html">属性</a>。</p>
<p>当配置谓词为真时，此属性展开为谓词后列出的属性。例如，下面的模块可以在 <code>linux.rs</code> 或 <code>windows.rs</code> 中都能找到。</p>
<!-- ignore: `mod` needs multiple files -->
<pre><code class="language-rust ignore">#[cfg_attr(target_os = &quot;linux&quot;, path = &quot;linux.rs&quot;)]
#[cfg_attr(windows, path = &quot;windows.rs&quot;)]
mod os;
</code></pre>
<p>可以列出零个、一个或多个属性。多个属性将各自展开为单独的属性。例如：</p>
<!-- ignore: fake attributes -->
<pre><code class="language-rust ignore">#[cfg_attr(feature = &quot;magic&quot;, sparkles, crackles)]
fn bewitched() {}

// 当启用了 `magic` 特性时, 上面的代码将会被展开为:
#[sparkles]
#[crackles]
fn bewitched() {}
</code></pre>
<blockquote>
<p><strong>注意</strong>: <code>cfg_attr</code> 能展开为另一个 <code>cfg_attr</code>。比如：<br />
<code>#[cfg_attr(target_os = &quot;linux&quot;, cfg_attr(feature = &quot;multithreaded&quot;, some_other_attribute))]</code> <br />
这个是合法的。这个示例等效于：<br />
<code>#[cfg_attr(all(target_os = &quot;linux&quot;, feature =&quot;multithreaded&quot;), some_other_attribute)]</code>.</p>
</blockquote>
<p><code>cfg_attr</code> 属性允许在任何允许属性的地方上使用。</p>
<h3><a class="header" href="#the-cfg-macro" id="the-cfg-macro">The <code>cfg</code> macro</a></h3>
<h3><a class="header" href="#cfg宏" id="cfg宏"><code>cfg</code>宏</a></h3>
<p>内置的 <code>cfg</code>宏接受单个配置谓词，当谓词为真时计算为 <code>true</code> 字面量，当谓词为假时计算为 <code>false</code> 字面量。</p>
<p>例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let machine_kind = if cfg!(unix) {
  &quot;unix&quot;
} else if cfg!(windows) {
  &quot;windows&quot;
} else {
  &quot;unknown&quot;
};

println!(&quot;I'm running on a {} machine!&quot;, machine_kind);
<span class="boring">}
</span></code></pre></pre>
<div class="footnote-definition" id="target-triple"><sup class="footnote-definition-label">1</sup>
<p>首先给出 <em>目标三元组</em> 的参考资料地址：https://www.bookstack.cn/read/rCore_tutorial_doc/d997e9cbdfeef7d4.md。<br />
接下来为防止该地址失效，我用自己的理解简单重复一下我对这个名词的理解:<br />
目标三元组可以理解为我们常说的平台信息，包含这些信息：第一项元素：CPU 架构；第二项元素：供应商；第三项元素：操作系统；第四项元素：ABI。<br />
Rust 下查看当前平台的三元组属性可以用 <code>rustc --version --verbose</code> 命令行。比如我在我工作机下下执行这行命令行的输出的 <code>host</code> 信息为：<code>host: x86_64-unknown-linux-gnu</code>，那我都工作机的目标三元组的信息就是：CPU 架构为 x86_64 ，供应商为 unknown ，操作系统为 linux ，ABI 为 gnu 。<br />
我另一台 windows 机器为：<code>host: x86_64-pc-windows-msvc</code>，那这台的目标三元组的信息为：CPU 架构为 x86_64 ，供应商为 pc ，操作系统为 windows ，ABI 为 msvc 。<br />
Rust 官方对一些平台提供了默认的目标三元组，我们可以通过 <code>rustc --print target-list</code> 命令来查看完整列表。</p>
</div>
<h1><a class="header" href="#items" id="items">Items</a></h1>
<h1><a class="header" href="#程序项" id="程序项">程序项</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items.md">items.md</a><br />
commit: b0e0ad6490d6517c19546b1023948986578fc378 <br />
本章译文最后维护日期：2020-11-8</p>
</blockquote>
<blockquote>
<p><strong><sup>句法:<sup></strong><br />
<em>Item</em>:<br />
   <a href="attributes.html"><em>OuterAttribute</em></a><sup>*</sup><br />
      <em>VisItem</em><br />
   | <em>MacroItem</em></p>
<p><em>VisItem</em>:<br />
   <a href="visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup><br />
   (<br />
          <a href="items/modules.html"><em>Module</em></a><br />
      | <a href="items/extern-crates.html"><em>ExternCrate</em></a><br />
      | <a href="items/use-declarations.html"><em>UseDeclaration</em></a><br />
      | <a href="items/functions.html"><em>Function</em></a><br />
      | <a href="items/type-aliases.html"><em>TypeAlias</em></a><br />
      | <a href="items/structs.html"><em>Struct</em></a><br />
      | <a href="items/enumerations.html"><em>Enumeration</em></a><br />
      | <a href="items/unions.html"><em>Union</em></a><br />
      | <a href="items/constant-items.html"><em>ConstantItem</em></a><br />
      | <a href="items/static-items.html"><em>StaticItem</em></a><br />
      | <a href="items/traits.html"><em>Trait</em></a><br />
      | <a href="items/implementations.html"><em>Implementation</em></a><br />
      | <a href="items/external-blocks.html"><em>ExternBlock</em></a><br />
   )</p>
<p><em>MacroItem</em>:<br />
      <a href="macros.html#macro-invocation"><em>MacroInvocationSemi</em></a><br />
   | <a href="macros-by-example.html"><em>MacroRulesDefinition</em></a></p>
</blockquote>
<p>*<a href="%E7%BF%BB%E8%AF%91%E8%AF%B4%E6%98%8E.html#%E5%B8%B8%E7%94%A8%E8%AF%8D%E7%BF%BB%E8%AF%91">程序项</a>*是 crate 的组成单元。程序项由一套嵌套的<a href="items/modules.html">模块</a>被组织在一个 crate 内。每个 crate 都有一个“最外层”的匿名模块；crate 中所有的程序项都在其 crate 的模块树中自己的<a href="paths.html">路径</a>。</p>
<p>程序项在编译时就完全确定下来了，通常在执行期间保持结构稳定，并可以驻留在只读内存中。</p>
<p>有以下几类程序项:</p>
<ul>
<li><a href="items/modules.html">模块</a></li>
<li><a href="items/extern-crates.html">外部crate(<code>extern crate</code>)声明</a></li>
<li><a href="items/use-declarations.html"><code>use</code>声明</a></li>
<li><a href="items/functions.html">函数定义</a></li>
<li><a href="items/type-aliases.html">类型定义</a></li>
<li><a href="items/structs.html">结构体定义</a></li>
<li><a href="items/enumerations.html">枚举定义</a></li>
<li><a href="items/unions.html">联合体定义</a></li>
<li><a href="items/constant-items.html">常量项</a></li>
<li><a href="items/static-items.html">静态项</a></li>
<li><a href="items/traits.html">trait定义</a></li>
<li><a href="items/implementations.html">实现</a></li>
<li><a href="items/external-blocks.html">外部块(<code>extern</code> blocks)</a></li>
</ul>
<p>有些程序项会形成子（数据）项声明的隐式作用域。换句话说，在一个函数或模块中，程序项的声明可以（在许多情况下）与语句、控制块、以及类似的能构成程序项主体的部件混合在一起。这些在作用域内的程序项的意义与在作用域外声明的程序项的意义相同（它仍然是静态项），只是该程序项在模块的命名空间中的<em>路径名</em>由封闭它的程序项的名称限定，或该程序项也可能是封闭它的程序项的私有程序项（比如函数的情况）。语法规范指定了子项声明可能出现的合法位置。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#modules" id="modules">Modules</a></h1>
<h1><a class="header" href="#模块" id="模块">模块</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/modules.md">modules.md</a><br />
commit: eabdf09207bf3563ae96db9d576de0758c413d5d <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<blockquote>
<p><strong><sup>句法:</sup></strong><br />
<em>Module</em> :<br />
      <code>unsafe</code><sup>?</sup> <code>mod</code> <a href="items/../identifiers.html">IDENTIFIER</a> <code>;</code><br />
   | <code>unsafe</code><sup>?</sup> <code>mod</code> <a href="items/../identifiers.html">IDENTIFIER</a> <code>{</code><br />
        <a href="items/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
        <a href="items/../items.html"><em>Item</em></a><sup>*</sup><br />
      <code>}</code></p>
</blockquote>
<p>模块是零个或多个<a href="items/../items.html">程序项</a>的容器。</p>
<p><em>模块项</em>是一个用花括号括起来的，有名称的，并以关键字 <code>mod</code> 作为前缀的模块。模块项将一个新的具名模块引入到组成 crate 的模块树中。模块可以任意嵌套。</p>
<p>模块的一个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>mod math {
    type Complex = (f64, f64);
    fn sin(f: f64) -&gt; f64 {
        /* ... */
<span class="boring">      unimplemented!();
</span>    }
    fn cos(f: f64) -&gt; f64 {
        /* ... */
<span class="boring">      unimplemented!();
</span>    }
    fn tan(f: f64) -&gt; f64 {
        /* ... */
<span class="boring">      unimplemented!();
</span>    }
}
<span class="boring">}
</span></code></pre></pre>
<p>模块和类型共享相同的命名空间。禁止在同一个作用域中声明与此作用域下模块同名的具名类型(named type)：也就是说，类型定义、trait、结构体、枚举、联合体、类型参数或 crate 不能在其作用域中屏蔽此作用域中也生效的模块名称，反之亦然。使用 <code>use</code> 引入到当前作用域的程序项也受这个限制。</p>
<p>在句法上，关键字 <code>unsafe</code> 允许出现在关键字 <code>mod</code> 之前，但是在语义层面却会被弃用。这种设计允许宏在将关键字 <code>unsafe</code> 从 token流中移除之前利用此句法来使用此关键字。</p>
<h2><a class="header" href="#module-source-filenames" id="module-source-filenames">Module Source Filenames</a></h2>
<h2><a class="header" href="#模块的源文件名" id="模块的源文件名">模块的源文件名</a></h2>
<p>没有代码体的模块是从外部文件加载的。当模块没有 <code>path</code> 属性限制时，文件的路径和逻辑上的<a href="items/../paths.html">模块路径</a>互为镜像。祖先模块的路径组件(path component)是此模块文件的目录，而模块的内容存在一个以该模块名为文件名，以 <code>.rs</code> 为扩展文件名的文件中。例如，下面的示例可以反映这种模块结构和文件系统结构相互映射的关系：</p>
<table><thead><tr><th>模块路径</th><th>文件系统路径</th><th>文件内容</th></tr></thead><tbody>
<tr><td><code>crate</code></td><td><code>lib.rs</code></td><td><code>mod util;</code></td></tr>
<tr><td><code>crate::util</code></td><td><code>util.rs</code></td><td><code>mod config;</code></td></tr>
<tr><td><code>crate::util::config</code></td><td><code>util/config.rs</code></td><td></td></tr>
</tbody></table>
<p>当一个目录下有一个名为 <code>mod.rs</code> 的源文件时，模块的文件名也可以和这个目录互相映射。上面的例子也可以用一个承载同一源码内容的名为 <code>util/mod.rs</code> 的实体文件来表达模块路径 <code>crate::util</code>。注意不允许 <code>util.rs</code> 和 <code>util/mod.rs</code> 同时存在。</p>
<blockquote>
<p><strong>注意</strong>：在<code>rustc</code> 1.30 版本之前，使用文件 <code>mod.rs</code> 是加载嵌套子模块的方法。现在鼓励使用新的命名约定，因为它更一致，并且可以避免在项目中搞出许多名为 <code>mod.rs</code> 的文件。</p>
</blockquote>
<h3><a class="header" href="#the-path-attribute" id="the-path-attribute">The <code>path</code> attribute</a></h3>
<h3><a class="header" href="#path属性" id="path属性"><code>path</code>属性</a></h3>
<p>用于加载外部文件模块的目录和文件可以受 <code>path</code>属性的影响。（或者说可以联合使用 <code>path</code>属性来重新指定那种没有代码体的模块声明的加载对象的文件路径。）</p>
<p>对于不在内联模块(inline module)块内的模块上的 <code>path</code>属性，此属性引入的文件的路径为相对于当前源文件所在的目录。例如，下面的代码片段将使用基于其所在位置的路径:</p>
<!-- ignore: requires external files -->
<pre><code class="language-rust ignore">#[path = &quot;foo.rs&quot;]
mod c;
</code></pre>
<table><thead><tr><th>Source File</th><th><code>c</code>'s File Location</th><th><code>c</code>'s Module Path</th></tr></thead><tbody>
<tr><td><code>src/a/b.rs</code></td><td><code>src/a/foo.rs</code></td><td><code>crate::a::b::c</code></td></tr>
<tr><td><code>src/a/mod.rs</code></td><td><code>src/a/foo.rs</code></td><td><code>crate::a::c</code></td></tr>
</tbody></table>
<p>对于处在内联模块块内的 <code>path</code>属性，此属性引入的文件的路径取决于 <code>path</code>属性所在的源文件的类型。（先对源文件进行分类，）“mod-rs”源文件是根模块（比如是 <code>lib.rs</code> 或 <code>main.rs</code>）和文件名为 <code>mod.rs</code> 的模块，“非mod-rs”源文件是所有其他模块文件。（那）在 mod-rs 文件中，内联模块块内的 <code>path</code> 属性（引入的文件的）路径是相对于 mod-rs 文件的目录（该目录包括作为目录的内联模块组件名）。对于非mod-rs 文件，除了路径以此模块名为目录前段外，其他是一样的。例如，下面的代码片段将使用基于其所在位置的路径：</p>
<!-- ignore: requires external files -->
<pre><code class="language-rust ignore">mod inline {
    #[path = &quot;other.rs&quot;]
    mod inner;
}
</code></pre>
<table><thead><tr><th>Source File</th><th><code>inner</code>'s File Location</th><th><code>inner</code>'s Module Path</th></tr></thead><tbody>
<tr><td><code>src/a/b.rs</code></td><td><code>src/a/b/inline/other.rs</code></td><td><code>crate::a::b::inline::inner</code></td></tr>
<tr><td><code>src/a/mod.rs</code></td><td><code>src/a/inline/other.rs</code></td><td><code>crate::a::inline::inner</code></td></tr>
</tbody></table>
<p>在内联模块和其内嵌模块上混合应用上述 <code>path</code>属性规则的一个例子（mod-rs 和非mod-rs 文件都适用）：</p>
<!-- ignore: requires external files -->
<pre><code class="language-rust ignore">#[path = &quot;thread_files&quot;]
mod thread { // 译者注：有模块要内联进来的内联模块
    // 从相对于当前源文件的目录下的 `thread_files/tls.rs` 文件里载 `local_data` 模块。
    #[path = &quot;tls.rs&quot;]
    mod local_data; // 译者注：内嵌模块
}
</code></pre>
<h2><a class="header" href="#attributes-on-modules" id="attributes-on-modules">Attributes on Modules</a></h2>
<h2><a class="header" href="#模块上的属性" id="模块上的属性">模块上的属性</a></h2>
<p>模块和所有程序项一样能接受外部属性。它们也能接受内部属性：可以在带有代码体的模块的 <code>{</code> 之后，也可以在模块源文件的开头（但须在可选的 BOM 和 shebang 之后）。</p>
<p>在模块中有意义的内置属性是 <a href="items/../conditional-compilation.html"><code>cfg</code></a>、<a href="items/../attributes/diagnostics.html#the-deprecated-attribute"><code>deprecated</code></a>、<a href="https://doc.rust-lang.org/rustdoc/the-doc-attribute.html"><code>doc</code></a>、<a href="items/../attributes/diagnostics.html#lint-check-attributes">lint检查类属性</a>、<a href="items/modules.html#the-path-attribute"><code>path</code></a> 和 <a href="items/../names/preludes.html#the-no_implicit_prelude-attribute"><code>no_implicit_prelude</code></a>。模块也能接受宏属性。</p>
<script>
(function() {
    var fragments = {
        "#prelude-items": "../names/preludes.html",
    };
    var target = fragments[window.location.hash];
    if (target) {
        var url = window.location.toString();
        var base = url.substring(0, url.lastIndexOf('/'));
        window.location.replace(base + "/" + target);
    }
})();
</script>
<h1><a class="header" href="#extern-crate-declarations" id="extern-crate-declarations">Extern crate declarations</a></h1>
<h1><a class="header" href="#外部crate声明" id="外部crate声明">外部crate声明</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/extern-crates.md">extern-crates.md</a><br />
commit: 0ce54e64e3c98d99862485c57087d0ab36f40ef0 <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<blockquote>
<p><strong><sup>句法:<sup></strong><br />
<em>ExternCrate</em> :<br />
   <code>extern</code> <code>crate</code> <em>CrateRef</em> <em>AsClause</em><sup>?</sup> <code>;</code></p>
<p><em>CrateRef</em> :<br />
   <a href="items/../identifiers.html">IDENTIFIER</a> | <code>self</code></p>
<p><em>AsClause</em> :<br />
   <code>as</code> ( <a href="items/../identifiers.html">IDENTIFIER</a> | <code>_</code> )</p>
</blockquote>
<p><em>外部crate(<code>extern crate</code>)声明</em>指定了对外部 crate 的依赖关系。（这种声明让）外部的 crate 作为外部crate(<code>extern crate</code>)声明中提供的<a href="items/../identifiers.html">标识符</a>被绑定到当前声明的作用域中。此外，如果 <code>extern crate</code> 出现在 crate的根模块中，那么此 crate名称也会被添加到<a href="items/../names/preludes.html#extern-prelude">外部预导入包</a>中，以便使其自动出现在所有模块的作用域中。<code>as</code>子句可用于将导入的 crate 绑定到不同的名称上。</p>
<p>外部crate 在编译时被解析为一个特定的 <code>soname</code><sup class="footnote-reference"><a href="#soname">1</a></sup>， 并且一个到此 <code>soname</code> 的运行时链接会传递给链接器，以便在运行时加载此 <code>soname</code>。<code>soname</code> 在编译时解析，方法是扫描编译器的库文件路径，匹配外部crate 的 <code>crateid</code>。因为<code>crateid</code> 是在编译时通过可选的 <code>crateid</code>属性声明的，所以如果外部 crate 没有提供 <code>crateid</code>， 则默认拿该外部crate 的 <code>name</code>属性值来和外部crate(<code>extern crate</code>)声明中的[标识符]绑定。</p>
<p>导入 <code>self</code> crate 会创建到当前 crate 的绑定。在这种情况下，必须使用 <code>as</code>子句指定要绑定到的名称。</p>
<p>三种外部crate(<code>extern crate</code>)声明的示例:</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">extern crate pcre;

extern crate std; // 等同于: extern crate std as std;

extern crate std as ruststd; // 使用其他名字去链接 'std'
</code></pre>
<p>当给 Rust crate 命名时，不允许使用连字符(<code>-</code>)。然而 Cargo 包却可以使用它们。在这种情况下，当 <code>Cargo.toml</code> 文件中没有指定 crate 名称时， Cargo 将透明地将 <code>-</code> 替换为 <code>_</code> 以供 Rust 源文件内的外部crate(<code>extern crate</code>)声明引用 (详见 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0940-hyphens-considered-harmful.md">RFC 940</a>)。</p>
<p>这有一个示例：</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">// 导入 Cargo 包 hello-world
extern crate hello_world; // 连字符被替换为下划线
</code></pre>
<h2><a class="header" href="#extern-prelude" id="extern-prelude">Extern Prelude</a></h2>
<h2><a class="header" href="#外部预导入包" id="外部预导入包">外部预导入包</a></h2>
<p>本节内容已经移入<a href="items/../names/preludes.html#extern-prelude">预导入包 — 外部预导入包</a>中了。</p>
<!-- 本节是为了让其他资料的链入链接不止于立即失效，一旦其他链接被更新，本节就会删除 -->
<h2><a class="header" href="#underscore-imports" id="underscore-imports">Underscore Imports</a></h2>
<h2><a class="header" href="#下划线导入" id="下划线导入">下划线导入</a></h2>
<p>外部的 crate依赖可以通过使用带有下划线形如 <code>extern crate foo as _</code> 的形式来声明，而无需将其名称绑定到当前作用域内。这种声明方式对于只需要 crate 被链接进来，但 crate 从不会被当前代码引用的情况可能很有用，并且还可以避免未使用的 lint 提醒。</p>
<p>下划线导入不会影响 <a href="items/../macros-by-example.html#the-macro_use-attribute"><code>macro_use</code>属性</a>的正常使用，这情况下使用 <code>macro_use</code>属性，宏名称仍会正常导入到 <a href="items/../names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a>中。</p>
<h2><a class="header" href="#the-no_link-attribute" id="the-no_link-attribute">The <code>no_link</code> attribute</a></h2>
<h2><a class="header" href="#no_link属性" id="no_link属性"><code>no_link</code>属性</a></h2>
<p>可以在外部项(<code>extern crate</code> item)上指定使用 <em><code>no_link</code>属性</em>，以防止此 crate 被链接到编译输出中。这通常用于加载一个 crate 而只访问它的宏。</p>
<div class="footnote-definition" id="soname"><sup class="footnote-definition-label">1</sup>
<p>译者注：这里的 <code>soname</code> 是 linux系统里的动态库文件的 soname。</p>
</div>
<script>
(function() {
    var fragments = {
        "#extern-prelude": "../names/preludes.html#extern-prelude",
    };
    var target = fragments[window.location.hash];
    if (target) {
        var url = window.location.toString();
        var base = url.substring(0, url.lastIndexOf('/'));
        window.location.replace(base + "/" + target);
    }
})();
</script><h1><a class="header" href="#use-declarations" id="use-declarations">Use declarations</a></h1>
<h1><a class="header" href="#use声明" id="use声明">Use声明</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/use-declarations.md">use-declarations.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法:</sup></strong><br />
<em>UseDeclaration</em> :<br />
   <code>use</code> <em>UseTree</em> <code>;</code></p>
<p><em>UseTree</em> :<br />
      (<a href="items/../paths.html#simple-paths"><em>SimplePath</em></a><sup>?</sup> <code>::</code>)<sup>?</sup> <code>*</code><br />
   | (<a href="items/../paths.html#simple-paths"><em>SimplePath</em></a><sup>?</sup> <code>::</code>)<sup>?</sup> <code>{</code> (<em>UseTree</em> ( <code>,</code>  <em>UseTree</em> )<sup>*</sup> <code>,</code><sup>?</sup>)<sup>?</sup> <code>}</code><br />
   | <a href="items/../paths.html#simple-paths"><em>SimplePath</em></a> ( <code>as</code> ( <a href="items/../identifiers.html">IDENTIFIER</a> | <code>_</code> ) )<sup>?</sup></p>
</blockquote>
<p><em>use声明</em>用来创建一个或多个与程序项<a href="items/../paths.html">路径</a>同义的本地名称绑定。通常使用 <code>use</code>声明来缩短引用模块所需的路径。这些声明可以出现在<a href="items/modules.html">模块</a>和<a href="items/../expressions/block-expr.html">块</a>中，但通常在作用域顶部。</p>
<p>use声明支持多种便捷方法:</p>
<ul>
<li>使用带有花括号的 glob-like(<code>::</code>) 句法 <code>use a::b::{c, d, e::f, g::h::i};</code> 来同时绑定一个系列有共同前缀的路径。</li>
<li>使用关键字 <code>self</code>，例如 <code>use a::b::{self, c, d::e};</code>，来同时绑定一系列有共同前缀和共同父模块的路径。</li>
<li>使用句法 <code>use p::q::r as x;</code> 将编译目标名称重新绑定为新的本地名称。这种也可以和上面两种方法一起使用：<code>use a::b::{self as ab, c as abc}</code>。</li>
<li>使用星号通配符句法 <code>use a::b::*;</code> 来绑定与给定前缀匹配的所有路径。</li>
<li>将前面的方法嵌套重复使用，例如 <code>use a::b::{self as ab, c, d::{*, e::f}};</code>。</li>
</ul>
<p><code>use</code>声明的一个示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">use std::option::Option::{Some, None};
use std::collections::hash_map::{self, HashMap};

fn foo&lt;T&gt;(_: T){}
fn bar(map1: HashMap&lt;String, usize&gt;, map2: hash_map::HashMap&lt;String, usize&gt;){}

fn main() {
    // 等价于 'foo(vec![std::option::Option::Some(1.0f64), std::option::Option::None]);'
    foo(vec![Some(1.0f64), None]);

    // `hash_map` 和 `HashMap` 在当前作用域内都有效.
    let map1 = HashMap::new();
    let map2 = hash_map::HashMap::new();
    bar(map1, map2);
}
</code></pre></pre>
<h2><a class="header" href="#use-visibility" id="use-visibility"><code>use</code> Visibility</a></h2>
<h2><a class="header" href="#use可见性" id="use可见性"><code>use</code>可见性</a></h2>
<p>与其他程序项一样，默认情况下，<code>use</code>声明对包含它的模块来说是私有的。同样的，如果使用关键字 <code>pub</code> 进行限定，<code>use</code>声明也可以是公有的。<code>use</code>声明可用于*重导出(re-expor)*名称。因此，公有的 <code>use</code>声明可以将某些公有名称重定向到不同的目标定义中：甚至是位于不同模块内具有私有可见性的规范路径定义中。如果这样的重定向序列形成一个循环或不能明确地解析，则会导致编译期错误。</p>
<p>重导出的一个示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">mod quux {
    pub use self::foo::{bar, baz};
    pub mod foo {
        pub fn bar() {}
        pub fn baz() {}
    }
}

fn main() {
    quux::bar();
    quux::baz();
}
</code></pre></pre>
<p>在本例中，模块 <code>quux</code> 重导出了在模块 <code>foo</code> 中定义的两个公共名称。</p>
<h2><a class="header" href="#use-paths" id="use-paths"><code>use</code> Paths</a></h2>
<h2><a class="header" href="#use路径" id="use路径"><code>use</code>路径</a></h2>
<blockquote>
<p><strong>注意</strong>：本章节内容还不完整。</p>
</blockquote>
<p>一些正常和不正常的使用 <code>use</code>程序项的例子：</p>
<!-- 注意: 这个例子在 2015 版或 2018 版都能正常工作。 -->
<pre><pre class="playground"><code class="language-rust edition2018"><span class="boring">#![allow(unused_imports)]
</span>use std::path::{self, Path, PathBuf};  // good: std 是一个 crate 名称
use crate::foo::baz::foobaz;    // good: foo 在当前 crate 的第一层

mod foo {

    pub mod example {
        pub mod iter {}
    }

    use crate::foo::example::iter; // good: foo 在当前 crate 的第一层
//  use example::iter;      // 在 2015 版里不行，2015 版里相对路径必须以 `self` 开头; 2018 版这样写没问题
    use self::baz::foobaz;  // good: `self` 指的是 'foo' 模块
    use crate::foo::bar::foobar;   // good: foo 在当前 crate 的第一层

    pub mod bar {
        pub fn foobar() { }
    }

    pub mod baz {
        use super::bar::foobar; // good: `super` 指的是 'foo' 模块
        pub fn foobaz() { }
    }
}

fn main() {}
</code></pre></pre>
<p>：</p>
<blockquote>
<p><strong>版本差异</strong>: 在 2015 版中，<code>use</code>路径也允许访问 crate 根模块中的程序项。继续使用上面的例子，那以下 <code>use</code>路径的用法在 2015 版中有效，在 2018 版中就无效了:</p>
<pre><pre class="playground"><code class="language-rust edition2015"><span class="boring">mod foo {
</span><span class="boring">    pub mod example { pub mod iter {} }
</span><span class="boring">    pub mod baz { pub fn foobaz() {} }
</span><span class="boring">}
</span>use foo::example::iter;
use ::foo::baz::foobaz;
<span class="boring">fn main() {}
</span></code></pre></pre>
<p>2015 版不允许用 use声明来引用<a href="items/../names/preludes.html#extern-prelude">外部预导入包</a>里的 crate。因此，在2015 版中仍然需要使用 <a href="items/extern-crates.html"><code>extern crate</code></a>声明，以便在 use声明中去引用外部 crate。从 2018 版开始，use声明可以像 <code>extern crate</code> 一样指定外部 crate 依赖关系。</p>
<p>在 2018 版中，如果本地程序项与外部的 crate 名称相同，那么使用该 crate 名称需要一个前导的 <code>::</code> 来明确地选择该 crate 名称。这种做法是为了与未来可能发生的更改保持兼容。<!-- uniform_paths future-proofing --></p>
<pre><pre class="playground"><code class="language-rust edition2018">// use std::fs; // 错误, 这样有歧义.
use ::std::fs;  // 从`std` crate 里导入, 不是下面这个 mod.
use self::std::fs as self_fs;  // 从下面这个 mod 导入.

mod std {
    pub mod fs {}
}
<span class="boring">fn main() {}
</span></code></pre></pre>
</blockquote>
<h2><a class="header" href="#underscore-imports-1" id="underscore-imports-1">Underscore Imports</a></h2>
<h2><a class="header" href="#下划线导入-1" id="下划线导入-1">下划线导入</a></h2>
<p>通过使用形如为 <code>use path as _</code> 的带下划线的 use声明，可以在不绑定名称的情况下导入程序项。这对于导入一个 trait 特别有用，这样就可以在不导入 trait 的 symbol 的情况下使用这个 trait 的方法，例如，如果 trait 的 symbol 可能与另一个 symbol 冲突。再一个例子是链接外部的 crate 而不导入其名称。</p>
<p>使用星号全局导入(Asterisk glob imports,即 <code>::*</code>)句法将以 <code>_</code> 的形式导入能匹配到的所有程序项，但这些程序项在当前作用域中将处于不可命名的状态。</p>
<pre><pre class="playground"><code class="language-rust edition2018">mod foo {
    pub trait Zoo {
        fn zoo(&amp;self) {}
    }

    impl&lt;T&gt; Zoo for T {}
}

use self::foo::Zoo as _;
struct Zoo;  // 下划线形式的导入就是为了避免和这个程序项在名字上起冲突

fn main() {
    let z = Zoo;
    z.zoo();
}
</code></pre></pre>
<p>在宏扩展之后会创建一些惟一的、不可命名的 symbols，这样宏就可以安全地扩展出(emit)对 <code>_</code> 导入的多个引用。例如，下面代码不应该产生错误:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! m {
    ($item: item) =&gt; { $item $item }
}

m!(use std as _;);
// 这会扩展出:
// use std as _;
// use std as _;
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#functions" id="functions">Functions</a></h1>
<h1><a class="header" href="#函数" id="函数">函数</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/functions.md">functions.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Function</em> :<br />
   <em>FunctionQualifiers</em> <code>fn</code> <a href="items/../identifiers.html">IDENTIFIER</a> <a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup><br />
      <code>(</code> <em>FunctionParameters</em><sup>?</sup> <code>)</code><br />
      <em>FunctionReturnType</em><sup>?</sup> <a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup><br />
      ( <a href="items/../expressions/block-expr.html"><em>BlockExpression</em></a> | <code>;</code> )</p>
<p><em>FunctionQualifiers</em> :<br />
   <code>const</code><sup>?</sup> <code>async</code><sup class="footnote-reference"><a href="#async-edition">1</a></sup><sup>?</sup> <code>unsafe</code><sup>?</sup> (<code>extern</code> <em>Abi</em><sup>?</sup>)<sup>?</sup></p>
<p><em>Abi</em> :<br />
   <a href="items/../tokens.html#string-literals">STRING_LITERAL</a> | <a href="items/../tokens.html#raw-string-literals">RAW_STRING_LITERAL</a></p>
<p><em>FunctionParameters</em> :<br />
      <em>SelfParam</em> <code>,</code><sup>?</sup><br />
   | (<em>SelfParam</em> <code>,</code>)<sup>?</sup> <em>FunctionParam</em> (<code>,</code> <em>FunctionParam</em>)<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>SelfParam</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> ( <em>ShorthandSelf</em> | <em>TypedSelf</em> )</p>
<p><em>ShorthandSelf</em> :<br />
    (<code>&amp;</code> | <code>&amp;</code> <a href="items/../trait-bounds.html"><em>Lifetime</em></a>)<sup>?</sup> <code>mut</code><sup>?</sup> <code>self</code></p>
<p><em>TypedSelf</em> :<br />
   <code>mut</code><sup>?</sup> <code>self</code> <code>:</code> <a href="items/../types.html#type-expressions"><em>Type</em></a></p>
<p><em>FunctionParam</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> (
<em>FunctionParamPattern</em> | <code>...</code> | <a href="items/../types.html#type-expressions"><em>Type</em></a> <sup class="footnote-reference"><a href="#fn-param-2015">2</a></sup>
)</p>
<p><em>FunctionParamPattern</em> :<br />
   <a href="items/../patterns.html"><em>PatternNoTopAlt</em></a> <code>:</code> ( <a href="items/../types.html#type-expressions"><em>Type</em></a> | <code>...</code> )</p>
<p><em>FunctionReturnType</em> :<br />
   <code>-&gt;</code> <a href="items/../types.html#type-expressions"><em>Type</em></a></p>
<div class="footnote-definition" id="async-edition"><sup class="footnote-definition-label">1</sup>
<p>限定符<code>async</code>不能在 2015版中使用。</p>
</div>
<div class="footnote-definition" id="fn-param-2015"><sup class="footnote-definition-label">2</sup>
<p>在2015版中，只有类型的函数参数只允许出现在<a href="items/traits.html">trait项</a>的关联函数中。</p>
</div>
</blockquote>
<p><em>函数</em>由一个<a href="items/../expressions/block-expr.html">块</a>以及一个名称和一组参数组成。除了名称，其他的都是可选的。函数使用关键字 <code>fn</code> 声明。函数可以声明一组<em>输入</em><a href="items/../variables.html"><em>变量</em></a>作为参数，调用者通过它向函数传递参数，函数完成后，它再将带有<em>输出</em><a href="items/../types.html#type-expressions"><em>类型</em></a>的结果值返回给调用者。</p>
<p>当一个<em>函数</em>被引用时，该函数会产生一个相应的零尺寸<a href="items/../types/function-item.html"><em>函数项类型(function item type)</em></a>的一等(first-class)<em>值</em>，调用该值就相当于直接调用该函数。</p>
<p>举个简单的定义函数的例子:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn answer_to_life_the_universe_and_everything() -&gt; i32 {
    return 42;
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#function-parameters" id="function-parameters">Function parameters</a></h2>
<h2><a class="header" href="#函数参数" id="函数参数">函数参数</a></h2>
<p>和 <code>let</code>绑定一样，函数参数是不可反驳型<a href="items/../patterns.html">模式</a>，所以任何在 let绑定中有效的模式都可以有效应用在函数参数上:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn first((value, _): (i32, i32)) -&gt; i32 { value }
<span class="boring">}
</span></code></pre></pre>
<p>如果第一个参数是一个<em>SelfParam</em>类型的参数，这表明该函数是一个<a href="items/associated-items.html#methods">方法</a>。带 self参数的函数只能在 <a href="items/traits.html">trait</a> 或<a href="items/implementations.html">实现</a>中作为<a href="items/associated-items.html#associated-functions-and-methods">关联函数</a>出现。</p>
<p>带有 <code>...</code>token 的参数表示此函数是一个<a href="items/external-blocks.html#variadic-functions">可变参数函数</a>，<code>...</code> 只能作为<a href="items/external-blocks.html">外部块</a>里的函数的最后一个参数使用。可变参数可以有一个可选标识符，例如 <code>args: ...</code>。</p>
<h2><a class="header" href="#function-body" id="function-body">Function body</a></h2>
<h2><a class="header" href="#函数体" id="函数体">函数体</a></h2>
<p>函数的块在概念上被包装进在一个块中，该块绑定该函数的参数模式，然后返回(<code>return</code>)该函数的块的值。这意味着如果轮到块的*尾部表达式(tail expression)*被求值计算了，该块将结束，求得的值将被返回给调用者。通常，程序执行时如果流碰到函数体中的显式返回表达式(return expression)，就会截断那个隐式的最终表达式的执行。</p>
<p>例如，上面例子里函数的行为就像下面被改写的这样:</p>
<!-- ignore: example expansion -->
<pre><code class="language-rust ignore">// argument_0 是调用者真正传过来的第一个参数
let (value, _) = argument_0;
return {
    value
};
</code></pre>
<p>没有主体块的函数以分号结束。这种形式只能出现在 <a href="items/traits.html">trait</a> 或<a href="items/external-blocks.html">外部块</a>中。</p>
<h2><a class="header" href="#generic-functions" id="generic-functions">Generic functions</a></h2>
<h2><a class="header" href="#泛型函数" id="泛型函数">泛型函数</a></h2>
<p><em>泛型函数</em>允许在其签名中出现一个或多个<em>参数化类型(parameterized types)</em>。每个类型参数必须在函数名后面的尖括号封闭逗号分隔的列表中显式声明。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// foo 是建立在 A 和 B 基础上的泛型函数

fn foo&lt;A, B&gt;(x: A, y: B) {
<span class="boring">}
</span><span class="boring">}
</span></code></pre></pre>
<p>在函数签名上和函数体内部，类型参数的名称可以被用作类型名。可以为类型参数指定 <a href="items/traits.html">trait</a>约束，以允许对该类型的值调用这些 trait 的方法。这种约束是使用 <code>where</code>句法指定的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::fmt::Debug;
</span>fn foo&lt;T&gt;(x: T) where T: Debug {
<span class="boring">}
</span><span class="boring">}
</span></code></pre></pre>
<p>当使用泛型函数时，它的（类型参数的）类型会基于调用的上下文被实例化。例如，这里调用 <code>foo</code> 函数:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::fmt::Debug;

fn foo&lt;T&gt;(x: &amp;[T]) where T: Debug {
    // 省略细节
}

foo(&amp;[1, 2]);
<span class="boring">}
</span></code></pre></pre>
<p>将用 <code>i32</code> 实例化类型参数 <code>T</code>。</p>
<p>类型参数也可以在函数名之后的末段<a href="items/../paths.html">路径</a>组件(trailing path component，即 <code>::&lt;type&gt;</code>)中显式地提供。如果没有足够的上下文来确定类型参数，那么这可能是必要的。例如：<code>mem::size_of::&lt;u32&gt;() == 4</code>。</p>
<h2><a class="header" href="#extern-function-qualifier" id="extern-function-qualifier">Extern function qualifier</a></h2>
<h2><a class="header" href="#外部函数限定符" id="外部函数限定符">外部函数限定符</a></h2>
<p>外部函数限定符(<code>extern</code>)可以提供那些能通过特定 ABI 才能调用的函数的<em>定义</em>：</p>
<!-- ignore: fake ABI -->
<pre><code class="language-rust ignore">extern &quot;ABI&quot; fn foo() { /* ... */ }
</code></pre>
<p>这些通常与提供了函数<em>声明</em>的<a href="items/external-blocks.html">外部块</a>程序项一起使用，这样就可以调用此函数而不必同时提供此函数的<em>定义</em>：</p>
<!-- ignore: fake ABI -->
<pre><code class="language-rust ignore">extern &quot;ABI&quot; {
  fn foo(); /* no body */
}
unsafe { foo() }
</code></pre>
<p>当函数的 <code>FunctionQualifiers</code> 句法规则中的 <code>&quot;extern&quot; Abi?*</code> 选项被省略时，会默认使用 <code>&quot;Rust&quot;</code> 类型的 ABI。例如:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn foo() {}
<span class="boring">}
</span></code></pre></pre>
<p>等价于：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern &quot;Rust&quot; fn foo() {}
<span class="boring">}
</span></code></pre></pre>
<p>使用 <code>&quot;Rust&quot;</code> 之外的 ABI 可以让 Rust 中声明的函数被其他编程语言调用。比如下面声明了一个可以从 C 中调用的函数：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 使用 &quot;C&quot; ABI 声明一个函数
extern &quot;C&quot; fn new_i32() -&gt; i32 { 0 }

// 使用 &quot;stdcall&quot; ABI声明一个函数
<span class="boring">#[cfg(target_arch = &quot;x86_64&quot;)]
</span>extern &quot;stdcall&quot; fn new_i32_stdcall() -&gt; i32 { 0 }
<span class="boring">}
</span></code></pre></pre>
<p>与<a href="items/external-blocks.html">外部块</a>一样，当使用关键字 <code>extern</code> 而省略 <code>&quot;ABI</code> 时，ABI 默认使用的是 <code>&quot;C&quot;</code>。也就是说这个：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern fn new_i32() -&gt; i32 { 0 }
let fptr: extern fn() -&gt; i32 = new_i32;
<span class="boring">}
</span></code></pre></pre>
<p>等价于：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern &quot;C&quot; fn new_i32() -&gt; i32 { 0 }
let fptr: extern &quot;C&quot; fn() -&gt; i32 = new_i32;
<span class="boring">}
</span></code></pre></pre>
<p>非 <code>&quot;Rust&quot;</code> 的 ABI 函数不支持与 Rust 函数完全相同的展开(unwind)方式。因此展开进程过这类 ABI 函数的尾部时就会导致该进程被终止。（译者注：展开是逆向的。）</p>
<blockquote>
<p><strong>注意</strong>: <code>rustc</code> 背后的 LLVM 是通过执行一个非法指令来实现中止进程的功能的。</p>
</blockquote>
<h2><a class="header" href="#const-functions" id="const-functions">Const functions</a></h2>
<h2><a class="header" href="#常量函数" id="常量函数">常量函数</a></h2>
<p>使用关键字 <code>const</code> 限定的函数是<a href="items/../const_eval.html#const-functions">常量(const)函数</a>，<a href="items/structs.html">元组结构体</a>构造函数和<a href="items/enumerations.html">元组变体</a>构造函数也是如此。可以在<a href="items/../const_eval.html#const-context">常量上下文</a>中调用<em>常量函数</em>。</p>
<p>常量函数不允许是 <a href="items/functions.html#async-functions">async</a>类型的，并且不能使用 <a href="items/functions.html#extern-function-qualifier"><code>extern</code>函数限定符</a>。</p>
<h2><a class="header" href="#async-functions" id="async-functions">Async functions</a></h2>
<h2><a class="header" href="#异步函数" id="异步函数">异步函数</a></h2>
<p>函数可以被限定为异步的，这还可以与 <code>unsafe</code> 限定符结合在一起使用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>async fn regular_example() { }
async unsafe fn unsafe_example() { }
<span class="boring">}
</span></code></pre></pre>
<p>异步函数在调用时不起作用：相反，它们将参数捕获进一个 future。当该函数被轮询(polled)时，该 future 将执行该函数的函数体。</p>
<p>一个异步函数大致相当于返回一个以 <a href="items/../expressions/block-expr.html#async-blocks"><code>async move</code>块</a>为代码体的 <a href="items/../types/impl-trait.html"><code>impl Future</code></a> 的函数：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 源代码
async fn example(x: &amp;str) -&gt; usize {
    x.len()
}
<span class="boring">}
</span></code></pre></pre>
<p>大致等价于：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::future::Future;
</span>// 脱糖后的
fn example&lt;'a&gt;(x: &amp;'a str) -&gt; impl Future&lt;Output = usize&gt; + 'a {
    async move { x.len() }
}
<span class="boring">}
</span></code></pre></pre>
<p>实际的脱糖(desugaring)过程相当复杂：</p>
<ul>
<li>脱糖过程中的返回类型被假定捕获了 <em><code>async fn</code>声明</em>中的所有的生存期参数（包括省略的）。这可以在上面的脱糖示例中看到：（我们）显式地给它补上了一个生存期参数 <code>'a</code>，因此捕捉到 <code>'a</code>。</li>
<li>代码体中的 [<code>async move</code>块][async blocks]捕获所有函数参数，包括未使用或绑定到 <code>_</code> 模式的参数。参数销毁方面，除了销毁动作需要在返回的 future 完全执行(fully awaited)完成后才会发生外，可以确保异步函数参数的销毁顺序与函数非异步时的顺序相同。</li>
</ul>
<p>有关异步效果的详细信息，请参见 <a href="items/../expressions/block-expr.html#async-blocks"><code>async</code>块</a>。</p>
<blockquote>
<p><strong>版本差异</strong>: 异步函数只能从 Rust 2018 版才开始可用。</p>
</blockquote>
<h3><a class="header" href="#combining-async-and-unsafe" id="combining-async-and-unsafe">Combining <code>async</code> and <code>unsafe</code></a></h3>
<h3><a class="header" href="#async-和-unsafe-的联合使用" id="async-和-unsafe-的联合使用"><code>async</code> 和 <code>unsafe</code> 的联合使用</a></h3>
<p>声明一个既异步又非安全(<code>unsafe</code>)的函数是合法的。调用这样的函数是非安全的，并且（像任何异步函数一样）会返回一个 future。这个 future 只是一个普通的 future，因此“await”它不需要一个 <code>unsafe</code> 的上下文：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 等待这个返回的 future 相当于解引用 `x`。
//
// 安全条件: 在返回的 future 执行完成前，`x` 必须能被安全解引用
async unsafe fn unsafe_example(x: *const i32) -&gt; i32 {
  *x
}

async fn safe_example() {
    // 起初调用上面这个函数时需要一个非安全(`unsafe`)块：
    let p = 22;
    let future = unsafe { unsafe_example(&amp;p) };

    // 但是这里非安全(`unsafe`)块就没必要了，这里能正常读到 `p`:
    let q = future.await;
}
<span class="boring">}
</span></code></pre></pre>
<p>请注意，此行为是对返回 <code>impl Future</code> 的函数进行脱糖处理的结果——在本例中，我们脱糖处理生成的函数是一个非安全(<code>unsafe</code>)函数，这个非安全(<code>unsafe</code>)函数返回值与原始定义的函数的返回值仍保持一致。</p>
<p>非安全限定在异步函数上的使用方式与它在其他函数上的使用方式完全相同：只是它表示该函数会要求它的调用者提供一些额外的义务/条件来确保该函数的健全性(soundness)。与任何其他非安全函数一样，这些条件可能会超出初始调用本身——例如，在上面的代码片段中， 函数 <code>unsafe_example</code> 将指针 <code>x</code> 作为参数，然后（在执行 await 时）解引用了对该指针的引用。这意味着在 future 完成执行之前，<code>x</code> 必须是有效的，调用者有责任确保这一点。</p>
<h2><a class="header" href="#attributes-on-functions" id="attributes-on-functions">Attributes on functions</a></h2>
<h2><a class="header" href="#函数上的属性" id="函数上的属性">函数上的属性</a></h2>
<p>在函数上允许使用<a href="items/../attributes.html">外部属性</a>，也允许在<a href="items/../expressions/block-expr.html">函数体</a>中的 <code>{</code> 后面直接放置<a href="items/../attributes.html">内部属性</a>。</p>
<p>下面这个例子显示了一个函数的内部属性。该函数的文档中只会出现单词“Example”。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn documented() {
    #![doc = &quot;Example&quot;]
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：除了 lint检查类属性，函数上一般惯用的还是外部属性。</p>
</blockquote>
<p>在函数上有意义的属性是 <a href="items/../conditional-compilation.html#the-cfg-attribute"><code>cfg</code></a>、<a href="items/../conditional-compilation.html#the-cfg_attr-attribute"><code>cfg_attr</code></a>、<a href="items/../attributes/diagnostics.html#the-deprecated-attribute"><code>deprecated</code></a>、<a href="https://doc.rust-lang.org/rustdoc/the-doc-attribute.html"><code>doc</code></a>、<a href="items/../abi.html#the-export_name-attribute"><code>export_name</code></a>、<a href="items/../abi.html#the-link_section-attribute"><code>link_section</code></a>、<a href="items/../abi.html#the-no_mangle-attribute"><code>no_mangle</code></a>、<a href="items/../attributes/diagnostics.html#lint-check-attributes">lint检查类属性</a>、<a href="items/../attributes/diagnostics.html#the-must_use-attribute"><code>must_use</code></a>、<a href="items/../procedural-macros.html">过程宏属性</a>、<a href="items/../attributes/testing.html">测试类属性</a>和<a href="items/../attributes/codegen.html#optimization-hints">优化提示类属性</a>。函数也可以接受属性宏。</p>
<h2><a class="header" href="#attributes-on-function-parameters" id="attributes-on-function-parameters">Attributes on function parameters</a></h2>
<h2><a class="header" href="#函数参数上的属性" id="函数参数上的属性">函数参数上的属性</a></h2>
<p>函数参数允许使用<a href="items/../attributes.html">外部属性</a>，允许的<a href="items/../attributes.html#built-in-attributes-index">内置属性</a>仅限于 <code>cfg</code>、<code>cfg_attr</code>、<code>allow</code>、<code>warn</code>、<code>deny</code> 和 <code>forbid</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn len(
    #[cfg(windows)] slice: &amp;[u16],
    #[cfg(not(windows))] slice: &amp;[u8],
) -&gt; usize {
    slice.len()
}
<span class="boring">}
</span></code></pre></pre>
<p>应用于程序项的过程宏属性所使用的惰性辅助属性也是允许的，但是要注意不要在最终（输出）的 <code>TokenStream</code> 中包含这些惰性属性。</p>
<p>例如，下面的代码定义了一个未在任何地方正式定义的惰性属性 <code>some_inert_attribute</code>，而 <code>some_proc_macro_attribute</code> 过程宏负责检测它的存在，并从输出 token流 <code>TokenStream</code> 中删除它。</p>
<!-- ignore: requires proc macro -->
<pre><code class="language-rust ignore">#[some_proc_macro_attribute]
fn foo_oof(#[some_inert_attribute] arg: u8) {
}
</code></pre>
<h1><a class="header" href="#type-aliases" id="type-aliases">Type aliases</a></h1>
<h1><a class="header" href="#类型别名" id="类型别名">类型别名</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/type-aliases.md">type-aliases.md</a><br />
commit: 91fb8ee654a7eb566eea719e6f3404fff7789e48 <br />
本章译文最后维护日期：2021-06-27</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TypeAlias</em> :<br />
   <code>type</code> <a href="items/../identifiers.html">IDENTIFIER</a> <a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup>
( <code>:</code> <a href="items/../trait-bounds.html"><em>TypeParamBounds</em></a> )<sup>?</sup>
<a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup> ( <code>=</code> <a href="items/../types.html#type-expressions"><em>Type</em></a> )<sup>?</sup> <code>;</code></p>
</blockquote>
<p><em>类型别名</em>为现有的<a href="items/../types.html">类型</a>定义一个新名称。类型别名用关键字 <code>type</code> 声明。每个值都是一个唯一的特定的类型，但是可以实现几个不同的 trait，或者兼容几个不同的类型约束。</p>
<p>例如，下面将类型 <code>Point</code> 定义为类型 <code>(u8, u8)</code> 的同义词/别名：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>type Point = (u8, u8);
let p: Point = (41, 68);
<span class="boring">}
</span></code></pre></pre>
<p>元组结构体或单元结构体的类型别名不能用于充当该类型的构造函数:</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct MyStruct(u32);

use MyStruct as UseAlias;
type TypeAlias = MyStruct;

let _ = UseAlias(5); // OK
let _ = TypeAlias(5); // 无法工作
<span class="boring">}
</span></code></pre></pre>
<p>没有使用 <a href="items/../types.html#type-expressions"><em>Type</em></a> 来定义的类型别名只能作为 <a href="items/traits.html">trait</a> 中的<a href="items/associated-items.html#associated-types">关联类型</a>出现。</p>
<p>带 <a href="items/../trait-bounds.html"><em>TypeParamBounds</em></a> 的别名只能在 <a href="items/traits.html">trait</a> 中指定<a href="items/associated-items.html#associated-types">关联类型</a>时使用。</p>
<h1><a class="header" href="#structs" id="structs">Structs</a></h1>
<h1><a class="header" href="#结构体" id="结构体">结构体</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/structs.md">structs.md</a><br />
commit: 9d0aa172932ed15ec1b13556e6809b74bc58a02b <br />
本章译文最后维护日期：2021-1-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Struct</em> :<br />
      <em>StructStruct</em><br />
   | <em>TupleStruct</em></p>
<p><em>StructStruct</em> :<br />
   <code>struct</code>
<a href="items/../identifiers.html">IDENTIFIER</a> 
<a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup>
<a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup>
( <code>{</code> <em>StructFields</em><sup>?</sup> <code>}</code> | <code>;</code> )</p>
<p><em>TupleStruct</em> :<br />
   <code>struct</code>
<a href="items/../identifiers.html">IDENTIFIER</a> 
<a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup>
<code>(</code> <em>TupleFields</em><sup>?</sup> <code>)</code>
<a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup>
<code>;</code></p>
<p><em>StructFields</em> :<br />
   <em>StructField</em> (<code>,</code> <em>StructField</em>)<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>StructField</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup><br />
   <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup><br />
   <a href="items/../identifiers.html">IDENTIFIER</a> <code>:</code> <a href="items/../types.html#type-expressions"><em>Type</em></a></p>
<p><em>TupleFields</em> :<br />
   <em>TupleField</em> (<code>,</code> <em>TupleField</em>)<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>TupleField</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup><br />
   <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup><br />
   <a href="items/../types.html#type-expressions"><em>Type</em></a></p>
</blockquote>
<p><em>结构体</em>是一个使用关键字 <code>struct</code> 定义的标称型(nominal)<a href="items/../types/struct.html">结构体类型</a>。</p>
<p>结构体(<code>struct</code>)程序项的一个示例和它的使用方法：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Point {x: i32, y: i32}
let p = Point {x: 10, y: 11};
let px: i32 = p.x;
<span class="boring">}
</span></code></pre></pre>
<p><em>元组结构体</em>是一个标称型(nominal)<a href="items/../types/tuple.html">元组类型</a>，也是用关键字 <code>struct</code> 定义的。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Point(i32, i32);
let p = Point(10, 11);
let px: i32 = match p { Point(x, _) =&gt; x };
<span class="boring">}
</span></code></pre></pre>
<p>*单元结构体(unit-like struct)*是没有任何字段的结构体，它的定义完全不包含字段(fields)列表。这样的结构体隐式定义了其类型的同名常量（值）。例如:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Cookie;
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
<span class="boring">}
</span></code></pre></pre>
<p>等价于</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Cookie {}
const Cookie: Cookie = Cookie {};
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
<span class="boring">}
</span></code></pre></pre>
<p>结构体的精确内存布局还没有规范下来。目前可以使用 <a href="items/../type-layout.html#representations"><code>repr</code>属性</a>来指定特定的布局。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#enumerations" id="enumerations">Enumerations</a></h1>
<h1><a class="header" href="#枚举" id="枚举">枚举</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/enumerations.md">enumerations.md</a><br />
commit: d8cbe4eedb77bae3db9eff87b1238e7e23f6ae92 <br />
本章译文最后维护日期：2021-2-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Enumeration</em> :<br />
   <code>enum</code>
<a href="items/../identifiers.html">IDENTIFIER</a> 
<a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup>
<a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup>
<code>{</code> <em>EnumItems</em><sup>?</sup> <code>}</code></p>
<p><em>EnumItems</em> :<br />
   <em>EnumItem</em> ( <code>,</code> <em>EnumItem</em> )<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>EnumItem</em> :<br />
   <em>OuterAttribute</em><sup>*</sup> <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup><br />
   <a href="items/../identifiers.html">IDENTIFIER</a> ( <em>EnumItemTuple</em> | <em>EnumItemStruct</em>
| <em>EnumItemDiscriminant</em> )<sup>?</sup></p>
<p><em>EnumItemTuple</em> :<br />
   <code>(</code> <a href="items/structs.html"><em>TupleFields</em></a><sup>?</sup> <code>)</code></p>
<p><em>EnumItemStruct</em> :<br />
   <code>{</code> <a href="items/structs.html"><em>StructFields</em></a><sup>?</sup> <code>}</code></p>
<p><em>EnumItemDiscriminant</em> :<br />
   <code>=</code> <a href="items/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>枚举</em>，英文为 <em>enumeration</em>，常见其简写形式 <em>enum</em>，它同时定义了一个标称型(nominal)<a href="items/../types/enum.html">枚举类型</a>和一组<em>构造器</em>，这可用于创建或使用模式来匹配相应枚举类型的值。</p>
<p>枚举使用关键字 <code>enum</code> 来声明。</p>
<p><code>enum</code> 程序项的一个示例和它的使用方法：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Animal {
    Dog,
    Cat,
}

let mut a: Animal = Animal::Dog;
a = Animal::Cat;
<span class="boring">}
</span></code></pre></pre>
<p>枚举构造器可以带有具名字段或未具名字段：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Animal {
    Dog(String, f64),
    Cat { name: String, weight: f64 },
}

let mut a: Animal = Animal::Dog(&quot;Cocoa&quot;.to_string(), 37.2);
a = Animal::Cat { name: &quot;Spotty&quot;.to_string(), weight: 2.7 };
<span class="boring">}
</span></code></pre></pre>
<p>在这个例子中，<code>Cat</code> 是一个<em>类结构体枚举变体(struct-like enum variant)</em>，而 <code>Dog</code> 则被简单地称为枚举变体。每个枚举实例都有一个<em>判别值/判别式(discriminant)</em>，它是一个与此枚举实例关联的整数，用来确定它持有哪个变体。可以通过 <a href="https://doc.rust-lang.org/std/mem/fn.discriminant.html"><code>mem::discriminant</code></a> 函数来获得对这个判别值的不透明引用。</p>
<h2><a class="header" href="#custom-discriminant-values-for-fieldless-enumerations" id="custom-discriminant-values-for-fieldless-enumerations">Custom Discriminant Values for Fieldless Enumerations</a></h2>
<h2><a class="header" href="#为无字段枚举自定义判别值" id="为无字段枚举自定义判别值">为无字段枚举自定义判别值</a></h2>
<p>如果枚举的<em>任何</em>变体都没有附加字段，则可以直接设置和访问判别值。</p>
<p>可以使用操作符 <code>as</code> 通过<a href="items/../expressions/operator-expr.html#semantics">数值转换</a>将这些枚举类型转换为整型。枚举可以可选地指定每个判别值的具体值，方法是在变体名后面追加 <code>=</code> 和<a href="items/../const_eval.html#constant-expressions">常量表达式</a>。如果声明中的第一个变体未指定，则将其判别值设置为零。对于其他未指定的判别值，它比照前一个变体的判别值按 1 递增。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum Foo {
    Bar,            // 0
    Baz = 123,      // 123
    Quux,           // 124
}

let baz_discriminant = Foo::Baz as u32;
assert_eq!(baz_discriminant, 123);
<span class="boring">}
</span></code></pre></pre>
<p>尽管编译器被允许在实际的内存布局中使用较小的类型，但在<a href="items/../type-layout.html#the-default-representation">默认表形(default representation)</a>下，指定的判别值会被解释为一个 <code>isize</code> 值。也可以使用[原语表形(primitive representation)]或<a href="items/../type-layout.html#the-c-representation"><code>C</code>表形</a>来更改成大小可接受的值。</p>
<p>同一枚举中，两个变体使用相同的判别值是错误的。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum SharedDiscriminantError {
    SharedA = 1,
    SharedB = 1
}

enum SharedDiscriminantError2 {
    Zero,       // 0
    One,        // 1
    OneToo = 1  // 1 (和前值冲突！)
}
<span class="boring">}
</span></code></pre></pre>
<p>当前一个变体的判别值是当前表形允许的的最大值时，再使用默认判别值就也是错误的。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(u8)]
enum OverflowingDiscriminantError {
    Max = 255,
    MaxPlusOne // 应该是256，但枚举溢出了
}

#[repr(u8)]
enum OverflowingDiscriminantError2 {
    MaxMinusOne = 254, // 254
    Max,               // 255
    MaxPlusOne         // 应该是256，但枚举溢出了。
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#zero-variant-enums" id="zero-variant-enums">Zero-variant Enums</a></h2>
<h2><a class="header" href="#无变体枚举" id="无变体枚举">无变体枚举</a></h2>
<p>没有变体的枚举称为<em>零变体枚举/无变体枚举</em>。因为它们没有有效的值，所以不能被实例化。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum ZeroVariants {}
<span class="boring">}
</span></code></pre></pre>
<p>零变体枚举与 <a href="items/../types/never.html"><em>never类型</em></a>等效，但它不能被强转为其他类型。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">enum ZeroVariants {}
</span>let x: ZeroVariants = panic!();
let y: u32 = x; // 类型不匹配错误
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#variant-visibility" id="variant-visibility">Variant visibility</a></h2>
<h2><a class="header" href="#变体的可见性" id="变体的可见性">变体的可见性</a></h2>
<p>依照句法规则，枚举变体是允许有自己的[<em>可见性(visibility)</em>][Visibility]限定/注解(annotation)的，但当枚举被（句法分析程序）验证(validate)通过后，可见性注解又被弃用。因此，在源码解析层面，允许跨不同的上下文对其中不同类型的程序项使用统一的句法规则进行解析。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! mac_variant {
    ($vis:vis $name:ident) =&gt; {
        enum $name {
            $vis Unit,

            $vis Tuple(u8, u16),

            $vis Struct { f: u8 },
        }
    }
}

// 允许空 `vis`.
mac_variant! { E }

// 这种也行，因为这段代码在被验证通过前会被移除。
#[cfg(FALSE)]
enum E {
    pub U,
    pub(crate) T(u8),
    pub(super) T { f: String }
}
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#unions" id="unions">Unions</a></h1>
<h1><a class="header" href="#联合体" id="联合体">联合体</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/unions.md">unions.md</a><br />
commit: 7c6e0c00aaa043c89e0d9f07e78999268e8ac054 <br />
本章译文最后维护日期：2021-2-10</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Union</em> :<br />
   <code>union</code> <a href="items/../identifiers.html">IDENTIFIER</a> <a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup> <a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup>
<code>{</code><a href="items/structs.html"><em>StructFields</em></a> <code>}</code></p>
</blockquote>
<p>除了用 <code>union</code> 代替 <code>struct</code>外，联合体声明使用和结构体声明相同的句法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(C)]
union MyUnion {
    f1: u32,
    f2: f32,
}
<span class="boring">}
</span></code></pre></pre>
<p>联合体的关键特性是联合体的所有字段共享同一段存储。因此，对联合体的一个字段的写操作会覆盖其他字段，而联合体的尺寸由其尺寸最大的字段的尺寸所决定。</p>
<h2><a class="header" href="#initialization-of-a-union" id="initialization-of-a-union">Initialization of a union</a></h2>
<h2><a class="header" href="#联合体的初始化" id="联合体的初始化">联合体的初始化</a></h2>
<p>可以使用与结构体类型相同的句法创建联合体类型的值，但必须只能指定一个字段：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">union MyUnion { f1: u32, f2: f32 }
</span><span class="boring">
</span>let u = MyUnion { f1: 1 };
<span class="boring">}
</span></code></pre></pre>
<p>上面的表达式创建了一个类型为 <code>MyUnion</code> 的值，并使用字段 <code>f1</code> 初始化了其存储。可以使用与结构体字段相同的句法访问联合体：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">union MyUnion { f1: u32, f2: f32 }
</span><span class="boring">
</span><span class="boring">let u = MyUnion { f1: 1 };
</span>let f = unsafe { u.f1 };
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#reading-and-writing-union-fields" id="reading-and-writing-union-fields">Reading and writing union fields</a></h2>
<h2><a class="header" href="#读写联合体字段" id="读写联合体字段">读写联合体字段</a></h2>
<p>联合体没有“活跃字段(active field)”的概念。相反，每次访问联合体只是用访问所指定的字段的类型解释此联合体的存储。读取联合体的字段就是以当前读取字段的类型来解读此联合体的存储位。字段（间）可以有非零的偏移量存在（使用 <a href="items/../type-layout.html#reprc-unions">C表型</a>的除外）；在这种情况下，读取将从字段的相对偏移量的 bit 开始。程序员有责任确保此数据在当前字段类型下有效。否则会导致<a href="items/../behavior-considered-undefined.html">未定义行为(undefined behavior)</a>。例如，在 <a href="items/../types/boolean.html"><code>bool</code>类型</a>的字段下读取到数值 <code>3</code> 是未定义行为。实际上，对一个 <a href="items/../type-layout.html#reprc-unions">C表型</a>的联合体进行写操作，然后再从中读取，就好比从用于写入的类型到用于读取的类型的 <a href="https://doc.rust-lang.org/std/mem/fn.transmute.html"><code>transmute</code></a> 操作。</p>
<p>因此，所有的联合体字段的读取必须放在非安全(<code>unsafe</code>)块里：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">union MyUnion { f1: u32, f2: f32 }
</span><span class="boring">let u = MyUnion { f1: 1 };
</span><span class="boring">
</span>unsafe {
    let f = u.f1;
}
<span class="boring">}
</span></code></pre></pre>
<p>对实现了 <a href="https://doc.rust-lang.org/std/marker/trait.Copy.html"><code>Copy</code></a> trait 或 [<code>ManuallyDrop</code>][ManuallyDrop] trait 的联合体字段的写操作不需要事先的析构读操作，也因此这些写操作不必放在非安全(<code>unsafe</code>)块中。<sup class="footnote-reference"><a href="#译者备注">1</a></sup></p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::mem::ManuallyDrop;
</span>union MyUnion { f1: u32, f2: ManuallyDrop&lt;String&gt; }
let mut u = MyUnion { f1: 1 };

// 这些都不是必须要放在 `unsafe` 里的
u.f1 = 2;
u.f2 = ManuallyDrop::new(String::from(&quot;example&quot;));
<span class="boring">}
</span></code></pre></pre>
<p>通常，那些用到联合体的程序代码会先在非安全的联合体字段访问操作上提供一层安全包装，然后再使用。</p>
<h2><a class="header" href="#unions-and-drop" id="unions-and-drop">Unions and <code>Drop</code></a></h2>
<h2><a class="header" href="#联合体和-drop" id="联合体和-drop">联合体和 <code>Drop</code></a></h2>
<p>当一个联合体被销毁时，它无法知道需要销毁它的哪些字段。因此，所有联合体的字段都必须实现 <code>Copy</code> trait 或被包装进 <a href="https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html"><code>ManuallyDrop&lt;_&gt;</code></a>。这确保了联合体在超出作用域时不需要销毁任何内容。</p>
<p>与结构体和枚举一样，联合体也可以通过 <code>impl Drop</code> 手动定义被销毁时的具体动作。</p>
<h2><a class="header" href="#pattern-matching-on-unions" id="pattern-matching-on-unions">Pattern matching on unions</a></h2>
<h2><a class="header" href="#联合体上的模式匹配" id="联合体上的模式匹配">联合体上的模式匹配</a></h2>
<p>访问联合体字段的另一种方法是使用模式匹配。联合体字段上的模式匹配与结构体上的模式匹配使用相同的句法，只是这种模式只能一次指定一个字段。因为模式匹配就像使用特定字段来读取联合体，所以它也必须被放在非安全(<code>unsafe</code>)块中。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">union MyUnion { f1: u32, f2: f32 }
</span><span class="boring">
</span>fn f(u: MyUnion) {
    unsafe {
        match u {
            MyUnion { f1: 10 } =&gt; { println!(&quot;ten&quot;); }
            MyUnion { f2 } =&gt; { println!(&quot;{}&quot;, f2); }
        }
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>模式匹配可以将联合体作为更大的数据结构的一个字段进行匹配。特别是，当使用 Rust 联合体通过 FFI 实现 C标签联合体(C tagged union)时，这允许同时在标签和相应字段上进行匹配：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(u32)]
enum Tag { I, F }

#[repr(C)]
union U {
    i: i32,
    f: f32,
}

#[repr(C)]
struct Value {
    tag: Tag,
    u: U,
}

fn is_zero(v: Value) -&gt; bool {
    unsafe {
        match v {
            Value { tag: Tag::I, u: U { i: 0 } } =&gt; true,
            Value { tag: Tag::F, u: U { f: num } } if num == 0.0 =&gt; true,
            _ =&gt; false,
        }
    }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#references-to-union-fields" id="references-to-union-fields">References to union fields</a></h2>
<h2><a class="header" href="#引用联合体字段" id="引用联合体字段">引用联合体字段</a></h2>
<p>由于联合体字段共享存储，因此拥有对联合体一个字段的写访问权就同时拥有了对其所有其他字段的写访问权。因为这一事实，引用的借用检查规则必须调整。因此，如果联合体的一个字段是被出借，那么在相同的生存期内它的所有其他字段也都处于出借状态。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">union MyUnion { f1: u32, f2: f32 }
</span>// 错误: 不能同时对 `u` (通过 `u.f2`)拥有多余一次的可变借用
fn test() {
    let mut u = MyUnion { f1: 1 };
    unsafe {
        let b1 = &amp;mut u.f1;
//                    ---- 首次可变借用发生在这里 (通过 `u.f1`)
        let b2 = &amp;mut u.f2;
//                    ^^^^ 二次可变借用发生在这里 (通过 `u.f2`)
        *b1 = 5;
    }
//  - 首次借用在这里结束
    assert_eq!(unsafe { u.f1 }, 5);
}
<span class="boring">}
</span></code></pre></pre>
<p>如您所见，在许多方面（除了布局、安全性和所有权），联合体的行为与结构体完全相同，这很大程度上是因为联合体继承使用了结构体的句法的结果。对于 Rust 语言未明确提及的许多方面（比如隐私性(privacy)、名称解析、类型推断、泛型、trait实现、固有实现、一致性、模式检查等等）也是如此。</p>
<div class="footnote-definition" id="译者备注"><sup class="footnote-definition-label">1</sup>
<p>这句译者简单理解就是对已经初始化的变量再去覆写的时候要先去读一下这个变量代表的地址上的值的状态，如果有值，并且允许覆写，那 Rust 为防止内存泄漏就先执行那变量的析构行为（drop()），清空那个地址上的关联堆数据，再写入。我们这里对联合体的预设条件是此联合体值有 Copy特性，有 Copy特性了，对值的直接覆写不会造成内存泄漏，就不必调用析构行为，也不需要事先的非安全读操作了。对于这个问题<a href="https://learnku.com/docs/nomicon/2018">nomicon</a>的“未初始化内存”章有讲述，博主<a href="https://www.zhihu.com/people/crlf0710">CrLF0710</a>的两篇“学一点 Rust 内存模型会发生什么呢？”里也都有精彩讲解。</p>
</div>
<h1><a class="header" href="#constant-items" id="constant-items">Constant items</a></h1>
<h1><a class="header" href="#常量项" id="常量项">常量项</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/constant-items.md">constant-items.md</a><br />
commit: 761ad774fcb300f2b506fed7b4dbe753cda88d80 <br />
本章译文最后维护日期：2020-1-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ConstantItem</em> :<br />
   <code>const</code> ( <a href="items/../identifiers.html">IDENTIFIER</a> | <code>_</code> ) <code>:</code> <a href="items/../types.html#type-expressions"><em>Type</em></a> ( <code>=</code> <a href="items/../expressions.html"><em>Expression</em></a> )<sup>?</sup> <code>;</code></p>
</blockquote>
<p><em>常量项</em>是一个可选的具名 <em><a href="items/../const_eval.html#constant-expressions">常量值</a></em>，它与程序中的具体内存位置没有关联。无论常量在哪里使用，它们本质上都是内联的，这意味着当它们被使用时，都是直接被拷贝到相关的上下文中来使用的。这包括使用非拷贝(non-<a href="items/../special-types-and-traits.html#copy"><code>Copy</code></a>)类型的值和来自外部的 crate 的常量。对相同常量的引用不保证它们引用的是相同的内存地址。</p>
<p>常量必须显式指定数据类型。类型必须具有 <code>'static</code>生存期：程序初始化器(initializer)中的任何引用都必须具有 <code>'static</code>生存期。</p>
<p>常量可以引用其他常量的地址，在这种情况下，如果适用，该地址将具有省略的生存期，否则（在大多数情况下）默认为 <code>'static</code>生存期。（请参阅<a href="items/../lifetime-elision.html#static-lifetime-elision">静态生存期省略</a>。）但是，编译器仍有权多次调整转移该常量，因此引用的地址可能并不固定。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>const BIT1: u32 = 1 &lt;&lt; 0;
const BIT2: u32 = 1 &lt;&lt; 1;

const BITS: [u32; 2] = [BIT1, BIT2];
const STRING: &amp;'static str = &quot;bitstring&quot;;

struct BitsNStrings&lt;'a&gt; {
    mybits: [u32; 2],
    mystring: &amp;'a str,
}

const BITS_N_STRINGS: BitsNStrings&lt;'static&gt; = BitsNStrings {
    mybits: BITS,
    mystring: STRING,
};
<span class="boring">}
</span></code></pre></pre>
<p>常量表达式只能在<a href="items/traits.html">trait定义中省略</a>。</p>
<h2><a class="header" href="#constants-with-destructors" id="constants-with-destructors">Constants with Destructors</a></h2>
<h2><a class="header" href="#常量与析构函数" id="常量与析构函数">常量与析构函数</a></h2>
<p>常量可以包含析构函数。析构函数在值超出作用域时运行。<sup class="footnote-reference"><a href="#译者备注">1</a></sup></p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct TypeWithDestructor(i32);

impl Drop for TypeWithDestructor {
    fn drop(&amp;mut self) {
        println!(&quot;Dropped. Held {}.&quot;, self.0);
    }
}

const ZERO_WITH_DESTRUCTOR: TypeWithDestructor = TypeWithDestructor(0);

fn create_and_drop_zero_with_destructor() {
    let x = ZERO_WITH_DESTRUCTOR;
    // x 在函数的结尾处通过调用 drop 方法被销毁。
    // 打印出 &quot;Dropped. Held 0.&quot;.
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#unnamed-constant" id="unnamed-constant">Unnamed constant</a></h2>
<h2><a class="header" href="#未命名常量" id="未命名常量">未命名常量</a></h2>
<p>不同于<a href="items/../glossary.html#associated-item">关联</a>常量(associated constant)，<a href="items/../glossary.html#free-item">自由</a>常量(free constant)可以使用下划线来命名。例如:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>const _: () =  { struct _SameNameTwice; };

// OK 尽管名称和上面的一样：
const _: () =  { struct _SameNameTwice; };
<span class="boring">}
</span></code></pre></pre>
<p>与<a href="items/use-declarations.html#underscore-imports">下划线导入</a>一样，宏可以多次安全地在同一作用域中扩展出相同的未具名常量。例如，以下内容不应该产生错误:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! m {
    ($item: item) =&gt; { $item $item }
}

m!(const _: () = (););
// 这会展开出：
// const _: () = ();
// const _: () = ();
<span class="boring">}
</span></code></pre></pre>
<div class="footnote-definition" id="译者备注"><sup class="footnote-definition-label">1</sup>
<p>在程序退出前，析构销毁的只是其中的一份拷贝；这句还有另一层含义是常量在整个程序结束时会调用析构函数。</p>
</div>
<!-- 2021-1-17-->
<!-- checked -->
<h1><a class="header" href="#static-items" id="static-items">Static items</a></h1>
<h1><a class="header" href="#静态项" id="静态项">静态项</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/static-items.md">static-items.md</a><br />
commit: bbb69d1e29ff3dc3acaa3f0011bf9b1c9991322c <br />
本章译文最后维护日期：2021-07-04</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>StaticItem</em> :<br />
   <code>static</code> <code>mut</code><sup>?</sup> <a href="items/../identifiers.html">IDENTIFIER</a> <code>:</code> <a href="items/../types.html#type-expressions"><em>Type</em></a>
( <code>=</code> <a href="items/../expressions.html"><em>Expression</em></a> )<sup>?</sup> <code>;</code></p>
</blockquote>
<p><em>静态项</em>类似于<a href="items/constant-items.html">常量项</a>，除了它在程序中表示一个精确的内存位置。所有对静态项的引用都指向相同的内存位置。静态项拥有 <code>'static</code> 生存期，它比 Rust 程序中的所有其他生存期都要长。静态项不会在程序结束时调用析构动作 <a href="items/../destructors.html"><code>drop</code></a>。</p>
<p>静态初始化器是在编译时求值的<a href="items/../const_eval.html#constant-expressions">常量表达式</a>。静态初始化器可以引用其他静态项。</p>
<p>包含非<a href="items/../interior-mutability.html">内部可变</a>类型的非 <code>mut</code> 静态项可以放在只读内存中。</p>
<p>所有访问静态项的操作都是安全的，但对静态项有一些限制：</p>
<ul>
<li>静态项的数据类型必须有 <code>Sync</code> trait约束，这样才可以让线程安全地访问。</li>
<li>常量项不能引用静态项。</li>
</ul>
<p>必须为自由静态项提供初始化表达式，但在<a href="items/external-blocks.html">外部块</a>中静态项必须省略初始化表达式。</p>
<h2><a class="header" href="#statics--generics" id="statics--generics">Statics &amp; generics</a></h2>
<h2><a class="header" href="#静态项和泛型" id="静态项和泛型">静态项和泛型</a></h2>
<p>在泛型作用域中（例如在包覆实现或默认实现中）定义的静态项将只会定义一个静态项，就好像该静态项定义是从当前作用域中拉入到模块内一样。<em>不会</em>出现程序项在单态化的过程中各自出现自己的独有静态项。</p>
<p>例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">use std::sync::atomic::{AtomicUsize, Ordering};

trait Tr {
    fn default_impl() {
        static COUNTER: AtomicUsize = AtomicUsize::new(0);
        println!(&quot;default_impl: counter was {}&quot;, COUNTER.fetch_add(1, Ordering::Relaxed));
    }

    fn blanket_impl();
}

struct Ty1 {}
struct Ty2 {}

impl&lt;T&gt; Tr for T {
    fn blanket_impl() {
        static COUNTER: AtomicUsize = AtomicUsize::new(0);
        println!(&quot;blanket_impl: counter was {}&quot;, COUNTER.fetch_add(1, Ordering::Relaxed));
    }
}

fn main() {
    &lt;Ty1 as Tr&gt;::default_impl();
    &lt;Ty2 as Tr&gt;::default_impl();
    &lt;Ty1 as Tr&gt;::blanket_impl();
    &lt;Ty2 as Tr&gt;::blanket_impl();
}
</code></pre></pre>
<p>以上会打印如下：</p>
<pre><code class="language-text">default_impl: counter was 0
default_impl: counter was 1
blanket_impl: counter was 0
blanket_impl: counter was 1
</code></pre>
<h2><a class="header" href="#mutable-statics" id="mutable-statics">Mutable statics</a></h2>
<h2><a class="header" href="#可变静态项" id="可变静态项">可变静态项</a></h2>
<p>如果静态项是用关键字 <code>mut</code> 声明的，则它允许被程序修改。Rust 的目标之一是使尽可能的避免出现并发 bug，那允许修改可变静态项显然是竞态(race conditions)或其他 bug 的一个重要来源。因此，读取或写入可变静态项变量时需要引入非安全(<code>unsafe</code>)块。应注意确保对可变静态项的修改相对于运行在同一进程中的其他线程来说是安全的。</p>
<p>尽管有这些缺点，可变静态项仍然非常有用。它们可以与 C库一起使用，也可以在外部(<code>extern</code>)块中从 C库中来绑定它。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn atomic_add(_: &amp;mut u32, _: u32) -&gt; u32 { 2 }
</span>
static mut LEVELS: u32 = 0;

// 这违反了不共享状态的思想，而且它在内部不能防止竞争，所以这个函数是非安全的(`unsafe`)
unsafe fn bump_levels_unsafe1() -&gt; u32 {
    let ret = LEVELS;
    LEVELS += 1;
    return ret;
}

// 这里我们假设有一个返回旧值的 atomic_add 函数，这个函数是“安全的(safe)”，
// 但是返回值可能不是调用者所期望的，所以它仍然被标记为 `unsafe`
unsafe fn bump_levels_unsafe2() -&gt; u32 {
    return atomic_add(&amp;mut LEVELS, 1);
}
<span class="boring">}
</span></code></pre></pre>
<p>除了可变静态项的类型不需要实现 <code>Sync</code> trait 之外，可变静态项与普通静态项具有相同的限制。</p>
<h2><a class="header" href="#using-statics-or-consts" id="using-statics-or-consts">Using Statics or Consts</a></h2>
<h2><a class="header" href="#使用常量项或静态项" id="使用常量项或静态项">使用常量项或静态项</a></h2>
<p>应该使用常量项还是应该使用静态项可能会令人困惑。一般来说，常量项应优先于静态项，除非以下情况之一成立：</p>
<ul>
<li>存储大量数据</li>
<li>需要静态项的存储地址不变的特性。</li>
<li>需要内部可变性。</li>
</ul>
<!-- 2021-1-17-->
<!-- checked -->
<h1><a class="header" href="#trait" id="trait">Trait</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/traits.md">traits.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Trait</em> :<br />
   <code>unsafe</code><sup>?</sup> <code>trait</code> <a href="items/../identifiers.html">IDENTIFIER</a> 
<a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup>
( <code>:</code> <a href="items/../trait-bounds.html"><em>TypeParamBounds</em></a><sup>?</sup> )<sup>?</sup>
<a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup> <code>{</code><br />
     <a href="items/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
     <a href="items/associated-items.html"><em>AssociatedItem</em></a><sup>*</sup><br />
   <code>}</code></p>
</blockquote>
<p><em>trait</em> 描述类型可以实现的抽象接口。这类接口由三种<a href="items/associated-items.html">关联程序项(associated items)</a>组成，它们分别是：</p>
<ul>
<li><a href="items/associated-items.html#associated-functions-and-methods">函数</a></li>
<li><a href="items/associated-items.html#associated-types">类型</a></li>
<li><a href="items/associated-items.html#associated-constants">常量</a></li>
</ul>
<p>所有 trait 都定义了一个隐式类型参数 <code>Self</code> ，它指向“实现此接口的类型”。trait 还可能包含额外的类型参数。这些类型参数，包括 <code>Self</code> 在内，都可能会<a href="items/generics.html">跟正常类型参数一样</a>受到其他 trait 的约束。</p>
<p>trait 需要具体的类型去实现，具体的实现方法是通过该类型的各种独立实现(implementations)来完成的。</p>
<p>trait函数可以通过使用分号代替函数体来省略函数体。这表明此 trait的实现必须去定义实现该函数。如果 trait函数定义了一个函数体，那么这个定义就会作为任何不覆盖它的实现的默认函数实现。类似地，关联常量可以省略等号和表达式，以指示相应的实现必须定义该常量值。关联类型不能定义类型，只能在实现中指定类型。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 有定义和没有定义的相关联trait项的例子
trait Example {
    const CONST_NO_DEFAULT: i32;
    const CONST_WITH_DEFAULT: i32 = 99;
    type TypeNoDefault;
    fn method_without_default(&amp;self);
    fn method_with_default(&amp;self) {}
}
<span class="boring">}
</span></code></pre></pre>
<p>Trait函数不能是 <a href="items/functions.html#async-functions"><code>async</code></a> 或 <a href="items/functions.html#const-functions"><code>const</code></a> 类型的。</p>
<h2><a class="header" href="#trait-bounds" id="trait-bounds">Trait bounds</a></h2>
<h2><a class="header" href="#trait约束" id="trait约束">trait约束</a></h2>
<p>泛型程序项可以使用 trait 作为其类型参数的<a href="items/../trait-bounds.html">约束</a>。</p>
<h2><a class="header" href="#generic-traits" id="generic-traits">Generic Traits</a></h2>
<h2><a class="header" href="#泛型trait" id="泛型trait">泛型trait</a></h2>
<p>可以为 trait 指定类型参数来使该 trait 成为泛型trait/泛型类型。这些类型参数出现在 trait 名称之后，使用与<a href="items/functions.html#generic-functions">泛型函数</a>相同的句法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Seq&lt;T&gt; {
    fn len(&amp;self) -&gt; u32;
    fn elt_at(&amp;self, n: u32) -&gt; T;
    fn iter&lt;F&gt;(&amp;self, f: F) where F: Fn(T);
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#object-safety" id="object-safety">Object Safety</a></h2>
<h2><a class="header" href="#对象安全条款" id="对象安全条款">对象安全条款</a></h2>
<p>对象安全的 trait 可以是 <a href="items/../types/trait-object.html">trait对象</a>的底层 trait。如果 trait 符合以下限定条件（在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md">RFC 255</a> 中定义），则认为它是<em>对象安全的(object safe)</em>：</p>
<ul>
<li>所有的超类trait<a href="items/traits.html#supertraits">supertraits</a> 也必须也是对象安全的。</li>
<li>超类trait 中不能有 <code>Sized</code>。也就是说不能有 <code>Self: Sized</code>约束。</li>
<li>它必须没有任何关联常量。</li>
<li>所有关联函数必须可以从 trait对象调度分派，或者是显式不可调度分派：
<ul>
<li>可调度分派函数要求：
<ul>
<li>不能有类型参数（尽管生存期参数可以有）</li>
<li>作为方法时，<code>Self</code> 只能出现在<a href="items/associated-items.html#methods">方法</a>的接受者(receiver)的类型里，其它地方不能使用 <code>Self</code>。</li>
<li>方法的接受者的类型必须是以下类型之一：
<ul>
<li><code>&amp;Self</code> (例如：<code>&amp;self</code>)</li>
<li><code>&amp;mut Self</code> (例如：<code>&amp;mut self</code>)</li>
<li><a href="items/../special-types-and-traits.html#boxt"><code>Box&lt;Self&gt;</code></a></li>
<li><a href="items/../special-types-and-traits.html#rct"><code>Rc&lt;Self&gt;</code></a></li>
<li><a href="items/../special-types-and-traits.html#arct"><code>Arc&lt;Self&gt;</code></a></li>
<li><a href="items/../special-types-and-traits.html#pinp"><code>Pin&lt;P&gt;</code></a> 当 <code>P</code> 是上面类型中的一种</li>
</ul>
</li>
<li>没有 <code>where Self: Sized</code>约束（即接受者的类型 <code>Self</code>(例如：<code>self</code>) 不能有 <code>Sized</code>约束）。</li>
</ul>
</li>
<li>显式不可调度分派函数要求：
<ul>
<li>有 <code>where Self: Sized</code>约束（即接受者的类型 <code>Self</code>(例如：<code>self</code>) 有 <code>Sized</code>约束）。</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::rc::Rc;
</span><span class="boring">use std::sync::Arc;
</span><span class="boring">use std::pin::Pin;
</span>// 对象安全的 trait 方法。
trait TraitMethods {
    fn by_ref(self: &amp;Self) {}
    fn by_ref_mut(self: &amp;mut Self) {}
    fn by_box(self: Box&lt;Self&gt;) {}
    fn by_rc(self: Rc&lt;Self&gt;) {}
    fn by_arc(self: Arc&lt;Self&gt;) {}
    fn by_pin(self: Pin&lt;&amp;Self&gt;) {}
    fn with_lifetime&lt;'a&gt;(self: &amp;'a Self) {}
    fn nested_pin(self: Pin&lt;Arc&lt;Self&gt;&gt;) {}
}
<span class="boring">struct S;
</span><span class="boring">impl TraitMethods for S {}
</span><span class="boring">let t: Box&lt;dyn TraitMethods&gt; = Box::new(S);
</span><span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 此 trait 是对象安全的，但不能在 trait对象上分发(dispatch)使用这些方法。
trait NonDispatchable {
    // 非方法不能被分发。
    fn foo() where Self: Sized {}
    // 在运行之前 Self 类型未知。
    fn returns(&amp;self) -&gt; Self where Self: Sized;
    // `other` 可能是另一具体类型的接受者。
    fn param(&amp;self, other: Self) where Self: Sized {}
    // 泛型与虚函数指针表(Virtual Function Pointer Table, vtable)不兼容。
    fn typed&lt;T&gt;(&amp;self, x: T) where Self: Sized {}
}

struct S;
impl NonDispatchable for S {
    fn returns(&amp;self) -&gt; Self where Self: Sized { S }
}
let obj: Box&lt;dyn NonDispatchable&gt; = Box::new(S);
obj.returns(); // 错误: 不能调用带有 Self 返回类型的方法
obj.param(S);  // 错误: 不能调用带有 Self 类型的参数的方法
obj.typed(1);  // 错误: 不能调用带有泛型类型参数的方法
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::rc::Rc;
</span>// 非对象安全的 trait
trait NotObjectSafe {
    const CONST: i32 = 1;  // 错误: 不能有关联常量

    fn foo() {}  // 错误: 关联函数没有 `Sized` 约束
    fn returns(&amp;self) -&gt; Self; // 错误: `Self` 在返回类型中 
    fn typed&lt;T&gt;(&amp;self, x: T) {} // 错误: 泛型类型参数
    fn nested(self: Rc&lt;Box&lt;Self&gt;&gt;) {} // 错误: 嵌套接受者还未被完全支持。（译者注：有限支持见上面的补充规则。）
}

struct S;
impl NotObjectSafe for S {
    fn returns(&amp;self) -&gt; Self { S }
}
let obj: Box&lt;dyn NotObjectSafe&gt; = Box::new(S); // 错误
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// Self: Sized trait 非对象安全的。
trait TraitWithSize where Self: Sized {}

struct S;
impl TraitWithSize for S {}
let obj: Box&lt;dyn TraitWithSize&gt; = Box::new(S); // 错误
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 如果有 `Self` 这样的泛型参数，那 trait 就是非对象安全的
trait Super&lt;A&gt; {}
trait WithSelf: Super&lt;Self&gt; where Self: Sized {}

struct S;
impl&lt;A&gt; Super&lt;A&gt; for S {}
impl WithSelf for S {}
let obj: Box&lt;dyn WithSelf&gt; = Box::new(S); // 错误: 不能使用 `Self` 作为类型参数
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#supertraits" id="supertraits">Supertraits</a></h2>
<h2><a class="header" href="#超类trait" id="超类trait">超类trait</a></h2>
<p><strong>超类trait</strong> 是类型为了实现某特定 trait 而需要一并实现的 trait。此外，在任何地方，如果<a href="items/generics.html">泛型</a>或 <a href="items/../types/trait-object.html">trait对象</a>被某个 trait约束，那这个泛型或 trait对象就可以访问这个<em>超类trait</em> 的关联程序项。</p>
<p>超类trait 是通过 trait 的 <code>Self</code>类型上的 trait约束来声明的，并且通过这种声明 trait约束的方式来传递这种超类trait 关系。一个 trait 不能是它自己的超类trait。</p>
<p>有超类trait 的 trait 称其为其超类trait 的<strong>子trait(subtrait)</strong>。</p>
<p>下面是一个声明 <code>Shape</code> 是 <code>Circle</code> 的超类trait 的例子。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Shape { fn area(&amp;self) -&gt; f64; }
trait Circle : Shape { fn radius(&amp;self) -&gt; f64; }
<span class="boring">}
</span></code></pre></pre>
<p>下面是同一个示例，除了改成使用 <a href="items/generics.html#where-clauses">where子句</a>来等效实现。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Shape { fn area(&amp;self) -&gt; f64; }
trait Circle where Self: Shape { fn radius(&amp;self) -&gt; f64; }
<span class="boring">}
</span></code></pre></pre>
<p>下面例子通过 <code>Shape</code> 的 <code>area</code> 函数为 <code>radius</code> 提供了一个默认实现：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Shape { fn area(&amp;self) -&gt; f64; }
</span>trait Circle where Self: Shape {
    fn radius(&amp;self) -&gt; f64 {
        // 因为 A = pi * r^2，所以通过代数推导得：r = sqrt(A / pi)
        (self.area() /std::f64::consts::PI).sqrt()
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>下一个示例调用了一个泛型参数的超类trait 上的方法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Shape { fn area(&amp;self) -&gt; f64; }
</span><span class="boring">trait Circle : Shape { fn radius(&amp;self) -&gt; f64; }
</span>fn print_area_and_radius&lt;C: Circle&gt;(c: C) {
    // 这里我们调用 `Circle` 的超类trait 的 area 方法。
    println!(&quot;Area: {}&quot;, c.area());
    println!(&quot;Radius: {}&quot;, c.radius());
}
<span class="boring">}
</span></code></pre></pre>
<p>类似地，这里是一个在 trait对象上调用超类trait 的方法的例子。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Shape { fn area(&amp;self) -&gt; f64; }
</span><span class="boring">trait Circle : Shape { fn radius(&amp;self) -&gt; f64; }
</span><span class="boring">struct UnitCircle;
</span><span class="boring">impl Shape for UnitCircle { fn area(&amp;self) -&gt; f64 { std::f64::consts::PI } }
</span><span class="boring">impl Circle for UnitCircle { fn radius(&amp;self) -&gt; f64 { 1.0 } }
</span><span class="boring">let circle = UnitCircle;
</span>let circle = Box::new(circle) as Box&lt;dyn Circle&gt;;
let nonsense = circle.radius() * circle.area();
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#unsafe-traits" id="unsafe-traits">Unsafe traits</a></h2>
<h2><a class="header" href="#非安全trait" id="非安全trait">非安全trait</a></h2>
<p>以关键字 <code>unsafe</code> 开头的 trait程序项表示<em>实现</em>该 trait 可能是<a href="items/../unsafety.html">非安全</a>的。使用正确实现的非安全trait 是安全的。<a href="items/implementations.html#trait-implementations">trait实现</a>也必须以关键字 <code>unsafe</code> 开头。</p>
<p><a href="items/../special-types-and-traits.html#sync"><code>Sync</code></a> 和 <a href="items/../special-types-and-traits.html#send"><code>Send</code></a> 是典型的非安全trait。</p>
<h2><a class="header" href="#parameter-patterns" id="parameter-patterns">Parameter patterns</a></h2>
<h2><a class="header" href="#参数模式" id="参数模式">参数模式</a></h2>
<p>（trait 中）没有代码体的函数声明或方法声明（的参数模式）只允许使用<a href="items/../identifiers.html">标识符/IDENTIFIER</a>模式 或 <code>_</code> <a href="items/../patterns.html#wildcard-pattern">通配符</a>模式。当前 <code>mut</code> <a href="items/../identifiers.html">IDENTIFIER</a> 还是允许的，但已被弃用，未来将成为一个硬编码错误(hard error)。</p>
<!-- https://github.com/rust-lang/rust/issues/35203 -->
<p>在 2015 版中，trait 的函数或方法的参数模式是可选的：</p>
<pre><pre class="playground"><code class="language-rust edition2015">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 2015版
trait T {
    fn f(i32);  // 不需要参数的标识符.
}
<span class="boring">}
</span></code></pre></pre>
<p>所有的参数模式被限制为下述之一：</p>
<ul>
<li><a href="items/../identifiers.html">IDENTIFIER</a></li>
<li><code>mut</code> <a href="items/../identifiers.html">IDENTIFIER</a></li>
<li><a href="items/../patterns.html#wildcard-pattern"><code>_</code></a></li>
<li><code>&amp;</code> <a href="items/../identifiers.html">IDENTIFIER</a></li>
<li><code>&amp;&amp;</code> <a href="items/../identifiers.html">IDENTIFIER</a></li>
</ul>
<p>（跟普通函数一样，）从 2018 版开始，（trait 中）函数或方法的参数模式不再是可选的。同时，也跟普通函数一样，（trait 中）函数或方法只要有代码体，其参数模式可以是任何不可反驳型模式。但如果没有代码体，上面列出的限制仍然有效。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait T {
    fn f1((a, b): (i32, i32)) {}
    fn f2(_: (i32, i32));  // 没有代码体不能使用元组模式。
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#item-visibility" id="item-visibility">Item visibility</a></h2>
<h2><a class="header" href="#程序项的可见性" id="程序项的可见性">程序项的可见性</a></h2>
<p>依照句法规定，trait程序项在语法上允许使用 <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a>句法的注释，但是当 trait 被（句法法分析程序）验证(validate)后，该可见性注释又被弃用。因此，在源码解析层面，可以在使用程序项的不同上下文中使用统一的语法对这些程序项进行解析。例如，空的 <code>vis</code> 宏匹配段选择器可以用于 trait程序项，而在其他允许使用非空可见性的情况下，也可使用这同一套宏规则。</p>
<pre><pre class="playground"><code class="language-rust edition2018">macro_rules! create_method {
    ($vis:vis $name:ident) =&gt; {
        $vis fn $name(&amp;self) {}
    };
}

trait T1 {
    // 只允许空 `vis`。
    create_method! { method_of_t1 }
}

struct S;

impl S {
    // 这里允许使用非空可见性。
    create_method! { pub method_of_s }
}

impl T1 for S {}

fn main() {
    let s = S;
    s.method_of_t1();
    s.method_of_s();
}
</code></pre></pre>
<div class="footnote-definition" id="译者备注"><sup class="footnote-definition-label">1</sup>
<p>两点提醒：所有 trait 都定义了一个隐式类型参数 <code>Self</code> ，它指向“实现此接口的类型”；trait 的 Self 默认满足：<code>Self: ?Sized</code></p>
</div>
<h1><a class="header" href="#implementations" id="implementations">Implementations</a></h1>
<h1><a class="header" href="#实现" id="实现">实现</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/implementations.md">implementations.md</a><br />
commit: d1f22f659fae9cfbeb9e45c8226d134d4a272586 <br />
本章译文最后维护日期：2021-5-29</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Implementation</em> :<br />
   <em>InherentImpl</em> | <em>TraitImpl</em></p>
<p><em>InherentImpl</em> :<br />
   <code>impl</code> <a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup> <a href="items/../types.html#type-expressions"><em>Type</em></a> <a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup> <code>{</code><br />
      <a href="items/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
      <a href="items/associated-items.html"><em>AssociatedItem</em></a><sup>*</sup><br />
   <code>}</code></p>
<p><em>TraitImpl</em> :<br />
   <code>unsafe</code><sup>?</sup> <code>impl</code> <a href="items/generics.html"><em>GenericParams</em></a><sup>?</sup> <code>!</code><sup>?</sup>
<a href="items/../paths.html#paths-in-types"><em>TypePath</em></a> <code>for</code> <a href="items/../types.html#type-expressions"><em>Type</em></a><br />
   <a href="items/generics.html#where-clauses"><em>WhereClause</em></a><sup>?</sup><br />
   <code>{</code><br />
      <a href="items/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
      <a href="items/associated-items.html"><em>AssociatedItem</em></a><sup>*</sup><br />
   <code>}</code></p>
</blockquote>
<p><em>实现</em>是将程序项与*实现类型(implementing type)*关联起来的程序项。实现使用关键字 <code>impl</code> 定义，它包含了属于当前实现的类型的实例的函数，或者包含了当前实现的类型本身的静态函数。</p>
<p>有两种类型的实现:</p>
<ul>
<li>固有实现(inherent implementations)</li>
<li><a href="items/traits.html">trait</a>实现(trait implementations)</li>
</ul>
<h2><a class="header" href="#inherent-implementations" id="inherent-implementations">Inherent Implementations</a></h2>
<h2><a class="header" href="#固有实现" id="固有实现">固有实现</a></h2>
<p>固有实现被定义为一段由关键字 <code>impl</code>，泛型类型声明，指向标称类型(nominal type)的路径，一个 where子句和一对花括号括起来的一组*类型关联项(associable items)*组成的序列。</p>
<p>（这里）<em>标称类型</em>也被称作<em>实现类型(implementing type)</em>；<em>类型关联项(associable items)<em>可理解为实现类型的各种</em>关联程序项(associated items)</em>。</p>
<p>固有实现将其包含的程序项与其的实现类型关联起来。固有实现可以包含<a href="items/associated-items.html#associated-functions-and-methods">关联函数</a>（包括<a href="items/associated-items.html#methods">方法</a>）和<a href="items/associated-items.html#associated-constants">关联常量</a>。固有实现不能包含关联类型别名。</p>
<p>关联程序项的<a href="items/../paths.html">路径</a>是其实现类型的所有（形式的）路径中的任一种，然后再拼接上这个关联程序项的标识符来作为整个路径的末段路径组件(final path component)。</p>
<p>类型可以有多个固有实现。但作为原始类型定义的实现类型必须与这些固有实现处在同一个 crate 里。</p>
<pre><pre class="playground"><code class="language-rust edition2018">pub mod color {
    // 译者添加的注释：这个结构体是 Color 的原始类型，是一个标称类型，也是后面两个实现的实现类型
    pub struct Color(pub u8, pub u8, pub u8);
    // 译者添加的注释：这个实现是 Color 的固有实现
    impl Color {
        // 译者添加的注释：类型关联项(associable items)
        pub const WHITE: Color = Color(255, 255, 255); 
    }
}

mod values {
    use super::color::Color;
    // 译者添加的注释：这个实现也是 Color 的固有实现
    impl Color {
        // 译者添加的注释：类型关联项(associable items)
        pub fn red() -&gt; Color {
            Color(255, 0, 0)
        }
    }
}

pub use self::color::Color;
fn main() {
    // 实现类型 和 固有实现 在同一个模块下。
    color::Color::WHITE;

    // 固有实现和类型声明不在同一个模块下，此时对通过固有实现关联进的程序项的存取仍通过指向实现类型的路径
    color::Color::red();

    // 实现类型重导出后，使用这类快捷路径效果也一样。
    Color::red();

    // 这个不行, 因为 `values` 非公有。
    // values::Color::red();
}
</code></pre></pre>
<h2><a class="header" href="#trait-implementations" id="trait-implementations">Trait Implementations</a></h2>
<h2><a class="header" href="#trait实现" id="trait实现">trait实现</a></h2>
<p><em>trait实现</em>的定义与固有实现类似，只是可选的泛型类型声明后须跟一个 <a href="items/traits.html">trait</a>，再后跟关键字 <code>for</code>，之后再跟一个指向标称类型的路径。</p>
<!-- 为理解这个，你必须回去查看一下上一节的内容 :( -->
<p>这里讨论的 trait 也被称为<em>被实现trait(implemented trait)</em>。实现类型去实现该被实现trait。</p>
<p>trait实现必须去定义被实现trait 声明里的所有非默认关联程序项，可以重新定义被实现trait 定义的默认关联程序项，但不能定义任何其他程序项。</p>
<p>关联程序项的完整路径为 <code>&lt;</code> 后跟实现类型的路径，再后跟 <code>as</code>，然后是指向 trait 的路径，再后跟 <code>&gt;</code>，这整体作为一个路径组件，然后再后接关联程序项自己的路径组件。</p>
<p><a href="items/traits.html#unsafe-traits">非安全(unsafe) trait</a> 需要 trait实现以关键字 <code>unsafe</code> 开头。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">#[derive(Copy, Clone)]
</span><span class="boring">struct Point {x: f64, y: f64};
</span><span class="boring">type Surface = i32;
</span><span class="boring">struct BoundingBox {x: f64, y: f64, width: f64, height: f64};
</span><span class="boring">trait Shape { fn draw(&amp;self, s: Surface); fn bounding_box(&amp;self) -&gt; BoundingBox; }
</span><span class="boring">fn do_draw_circle(s: Surface, c: Circle) { }
</span>struct Circle {
    radius: f64,
    center: Point,
}

impl Copy for Circle {}

impl Clone for Circle {
    fn clone(&amp;self) -&gt; Circle { *self }
}

impl Shape for Circle {
    fn draw(&amp;self, s: Surface) { do_draw_circle(s, *self); }
    fn bounding_box(&amp;self) -&gt; BoundingBox {
        let r = self.radius;
        BoundingBox {
            x: self.center.x - r,
            y: self.center.y - r,
            width: 2.0 * r,
            height: 2.0 * r,
        }
    }
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#trait-implementation-coherence" id="trait-implementation-coherence">Trait Implementation Coherence</a></h3>
<h3><a class="header" href="#trait实现的一致性" id="trait实现的一致性">trait实现的一致性</a></h3>
<p>一个 trait实现如果未通过孤儿规则(orphan rules)检查或有 trait实现重叠(implementations overlap)发生，则认为 trait实现不一致(incoherent)。</p>
<p>当两个实现各自的 <em>trait接口</em>集之间存在非空交集时即为这两个 trait实现 重叠了，（这种常情况下）这两个 trait实现可以用相同的类型来实例化。<!-- 这可能是错的？来源：对于输入类型参数，没有两个实现可以用相同的类型集实例化。 --></p>
<h4><a class="header" href="#orphan-rules" id="orphan-rules">Orphan rules</a></h4>
<h4><a class="header" href="#孤儿规则" id="孤儿规则">孤儿规则</a></h4>
<p>给定 <code>impl&lt;P1..=Pn&gt; Trait&lt;T1..=Tn&gt; for T0</code>，只有以下至少一种情况为真时，此 <code>impl</code> 才能成立：</p>
<ul>
<li>
<p><code>Trait</code> 是一个<a href="items/../glossary.html#local-trait">本地 trait</a></p>
</li>
<li>
<p>以下所有</p>
<ul>
<li><code>T0..=Tn</code> 中的类型至少有一种是<a href="items/../glossary.html#local-type">本地类型</a>。假设 <code>Ti</code> 是第一个这样的类型。</li>
<li>没有<a href="items/../glossary.html#uncovered-type">无覆盖类型</a>参数 <code>P1..=Pn</code> 会出现在 <code>T0..Ti</code> 里（注意 <code>Ti</code> 被排除在外）。</li>
</ul>
<p>（译者注：为理解上面两条规则，举几个例子、 <code>impl&lt;T&gt; ForeignTrait&lt;LocalType&gt; for ForeignType&lt;T&gt;</code> 这样的实现也是被允许的，而 <code>impl&lt;Vec&lt;T&gt;&gt; ForeignTrait&lt;LocalType&gt; for ForeignType&lt;T&gt;</code> 和 <code>impl&lt;T&gt; ForeignTrait&lt;Vec&lt;T&gt;&gt; for ForeignType&lt;T&gt;</code> 不被允许。）</p>
</li>
</ul>
<p>这里只有<em>无覆盖</em>类型参数的外观被限制（译者注：为方便理解“无覆盖类型参数”，译者提醒读者把它想象成上面译者举例中的 <code>T</code>）。注意，理解“无覆盖类型参数”时需要注意：为了保持一致性，<a href="items/../glossary.html#fundamental-type-constructors">基本类型</a>虽然外观形式特殊，但仍不认为是有覆盖的，比如 <code>Box&lt;T&gt;</code> 中的 <code>T</code> 就不认为是有覆盖的，<code>Box&lt;LocalType&gt;</code> 这样的就被认为是本地的。</p>
<h2><a class="header" href="#generic-implementations" id="generic-implementations">Generic Implementations</a></h2>
<h2><a class="header" href="#泛型实现" id="泛型实现">泛型实现</a></h2>
<p>实现可以带有<a href="items/generics.html">泛型参数</a>，这些参数可用在此实现中的其他地方。实现里的泛型参数直接写在关键字 <code>impl</code> 之后。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Seq&lt;T&gt; { fn dummy(&amp;self, _: T) { } }
</span>impl&lt;T&gt; Seq&lt;T&gt; for Vec&lt;T&gt; {
    /* ... */
}
impl Seq&lt;bool&gt; for u32 {
    /* 将整数处理为 bits 序列 */
}
<span class="boring">}
</span></code></pre></pre>
<p>如果泛型参数在以下情况下出现过，则其就能约束某个实现：</p>
<ul>
<li>需要被实现的 trait中存在泛型参数</li>
<li>实现类型中存在泛型参数</li>
<li>作为类型的<a href="items/../trait-bounds.html">约束</a>中的[关联类型]，该类型包含另一个约束实现的形参。</li>
</ul>
<p>类型和常量参数必须能在相应实现里体现出约束逻辑。如果关联类型中有生存期参数在使用，则该生存期的约束意义也必须在实现中体现。</p>
<p>约束必须被传递实现的例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Trait{}
</span><span class="boring">trait GenericTrait&lt;T&gt; {}
</span><span class="boring">trait HasAssocType { type Ty; }
</span><span class="boring">struct Struct;
</span><span class="boring">struct GenericStruct&lt;T&gt;(T);
</span><span class="boring">struct ConstGenericStruct&lt;const N: usize&gt;([(); N]);
</span>// T 通过作为 GenericTrait 的参数来体现约束
impl&lt;T&gt; GenericTrait&lt;T&gt; for i32 { /* ... */ }

// T 是作为 GenericStruct 的参数来体现约束
impl&lt;T&gt; Trait for GenericStruct&lt;T&gt; { /* ... */ }

// 同样，N 作为 ConstGenericStruct 的参数来体现约束
impl&lt;const N: usize&gt; Trait for ConstGenericStruct&lt;N&gt; { /* ... */ }

// T 通过类型 `U` 内的关联类型来体现约束，而 `U` 本身就是一个trait的泛型参数
impl&lt;T, U&gt; GenericTrait&lt;U&gt; for u32 where U: HasAssocType&lt;Ty = T&gt; { /* ... */ }

// 这个和前面一样，除了类型变为 `(U, isize)`。`U` 出现在包含 `T` 的类型中，而不是类型本身。
impl&lt;T, U&gt; GenericStruct&lt;U&gt; where (U, isize): HasAssocType&lt;Ty = T&gt; { /* ... */ }
<span class="boring">}
</span></code></pre></pre>
<p>约束未能被传递实现的例子：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 下面的都是错误的，因为它们的类型或常量参数没能被传递和实现约束

// T没有实现约束，因为实现内部根本就没有出现 T
impl&lt;T&gt; Struct { /* ... */ }

// 同样 N 也没有可能被实现
impl&lt;const N: usize&gt; Struct { /* ... */ }

// 在实现中使用了 T，但却并不约束此实现
impl&lt;T&gt; Struct {
    fn uses_t(t: &amp;T) { /* ... */ }
}

// 在 U 的约束中，T 被用作关联类型，但 U 本身在 Struct 里无法被约束
impl&lt;T, U&gt; Struct where U: HasAssocType&lt;Ty = T&gt; { /* ... */ }

// T 是在约束中使用了，但不是作为关联类型使用的，所以它没有实现约束
impl&lt;T, U&gt; GenericTrait&lt;U&gt; for u32 where U: GenericTrait&lt;T&gt; {}
<span class="boring">}
</span></code></pre></pre>
<p>允许的非约束生存期参数的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Struct;
</span>impl&lt;'a&gt; Struct {}
<span class="boring">}
</span></code></pre></pre>
<p>不允许的非约束生存期参数的示例：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Struct;
</span><span class="boring">trait HasAssocType { type Ty; }
</span>impl&lt;'a&gt; HasAssocType for Struct {
    type Ty = &amp;'a Struct;
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes-on-implementations" id="attributes-on-implementations">Attributes on Implementations</a></h2>
<h2><a class="header" href="#实现上的属性" id="实现上的属性">实现上的属性</a></h2>
<p>实现可以在关键字 <code>impl</code> 之前引入外部<a href="items/../attributes.html">属性</a>，在代码体内引入内部<a href="items/../attributes.html">属性</a>。内部属性必须位于任何关联程序项之前。这里有意义的属性有 <a href="items/../conditional-compilation.html"><code>cfg</code></a>、<a href="items/../attributes/diagnostics.html#the-deprecated-attribute"><code>deprecated</code></a>、<a href="https://doc.rust-lang.org/rustdoc/the-doc-attribute.html"><code>doc</code></a> 和 <a href="items/../attributes/diagnostics.html#lint-check-attributes">lint检查类属性</a>。</p>
<h1><a class="header" href="#external-blocks" id="external-blocks">External blocks</a></h1>
<h1><a class="header" href="#外部块" id="外部块">外部块</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/external-blocks.md">external-blocks.md</a><br />
commit: 761ad774fcb300f2b506fed7b4dbe753cda88d80 <br />
本章译文最后维护日期：2021-1-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ExternBlock</em> :<br />
   <code>unsafe</code><sup>?</sup> <code>extern</code> <a href="items/functions.html"><em>Abi</em></a><sup>?</sup> <code>{</code><br />
      <a href="items/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
      <em>ExternalItem</em><sup>*</sup><br />
   <code>}</code></p>
<p><em>ExternalItem</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> (<br />
         <a href="items/../macros.html#macro-invocation"><em>MacroInvocationSemi</em></a><br />
      | ( <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup> ( <a href="items/static-items.html"><em>StaticItem</em></a> | <a href="items/functions.html"><em>Function</em></a> ) )<br />
   )</p>
</blockquote>
<p>外部块提供未在当前 crate 中<em>定义</em>的程序项的<em>声明</em>，外部块是 Rust 外部函数接口的基础。这其实是某种意义上的不受安全检查的导入入口。</p>
<p>外部块里允许存在两种形式的程序项<em>声明</em>：<a href="items/functions.html">函数</a>和<a href="items/static-items.html">静态项</a>。只有在非安全(<code>unsafe</code>)上下文中才能调用在外部块中声明的函数或访问在外部块中声明的静态项。</p>
<p>在句法上，关键字 <code>unsafe</code> 允许出现在关键字 <code>extern</code> 之前，但是在语义层面却会被弃用。这种设计允许宏在将关键字 <code>unsafe</code> 从 token流中移除之前利用此句法来使用此关键字。</p>
<h2><a class="header" href="#functions-1" id="functions-1">Functions</a></h2>
<h2><a class="header" href="#函数-1" id="函数-1">函数</a></h2>
<p>外部块中的函数与其他 Rust函数的声明方式相同，但这里的函数不能有函数体，取而代之的是直接以分号结尾。外部块中的函数的参数不允许使用模式，只能使用<a href="items/../identifiers.html">标识符(IDENTIFIER)</a> 或 <code>_</code> 。函数限定符（<code>const</code>、<code>async</code>、<code>unsafe</code> 和 <code>extern</code>）也不允许在这里使用。</p>
<p>外部块中的函数可以被 Rust 代码调用，就跟调用在 Rust 中定义的函数一样。Rust 编译器会自动在 Rust ABI 和外部 ABI 之间进行转换。</p>
<p>在外部块中声明的函数隐式为非安全(<code>unsafe</code>)的。当强转为函数指针时，外部块中声明的函数的类型就为 <code>unsafe extern &quot;abi&quot; for&lt;'l1, ..., 'lm&gt; fn(A1, ..., An) -&gt; R</code>，其中 <code>'l1</code>，…<code>'lm</code> 是其生存期参数，<code>A1</code>，…，<code>An</code> 是该声明的参数的类型，<code>R</code> 是该声明的返回类型。</p>
<h2><a class="header" href="#statics" id="statics">Statics</a></h2>
<h2><a class="header" href="#静态项-1" id="静态项-1">静态项</a></h2>
<p><a href="items/static-items.html">静态项</a>在外部块内部与在外部块之外的声明方式相同，只是在外部块内部声明的静态项没有对应的初始化表达式。访问外部块中声明的静态项是 <code>unsafe</code> 的，不管它是否可变，因为没有任何保证来确保静态项的内存位模式(bit pattern)对声明它的类型是有效的，因为初始化这些静态项的可能是其他的任意外部代码（例如 C）。</p>
<p>就像外部块之外的<a href="items/static-items.html">静态项</a>，外部静态项可以是不可变的，也可以是可变的。在执行任何 Rust 代码之前，不可变外部静态项<em>必须</em>被初始化。也就是说，对于外部静态项，仅在 Rust 代码读取它之前对它进行初始化是不够的。</p>
<h2><a class="header" href="#abi" id="abi">ABI</a></h2>
<p>不指定 ABI 字符串的默认情况下，外部块会假定使用指定平台上的标准 C ABI 约定来调用当前的库。其他的 ABI 约定可以使用字符串 <code>abi</code> 来指定，具体如下所示：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 到 Windows API 的接口。（译者注：指定使用 stdcall调用约定去调用 Windows API）
extern &quot;stdcall&quot; { }
<span class="boring">}
</span></code></pre></pre>
<p>有三个 ABI 字符串是跨平台的，并且保证所有编译器都支持它们：</p>
<ul>
<li><code>extern &quot;Rust&quot;</code> -- 在任何 Rust 语言中编写的普通函数 <code>fn foo()</code> 默认使用的 ABI。</li>
<li><code>extern &quot;C&quot;</code> -- 这等价于 <code>extern fn foo()</code>；无论您的 C编译器支持什么默认 ABI。</li>
<li><code>extern &quot;system&quot;</code> -- 在 Win32 平台之外，中通常等价于 <code>extern &quot;C&quot;</code>。在 Win32 平台上，应该使用<code>&quot;stdcall&quot;</code>，或者其他应该使用的 ABI 字符串来链接它们自身的 Windows API。</li>
</ul>
<p>还有一些特定于平台的 ABI 字符串：</p>
<ul>
<li><code>extern &quot;cdecl&quot;</code> -- 通过 FFI 调用 x86_32 C 资源所使用的默认调用约定。</li>
<li><code>extern &quot;stdcall&quot;</code> -- 通过 FFI 调用 x86_32架构下的 Win32 API 所使用的默认调用约定 </li>
<li><code>extern &quot;win64&quot;</code> -- 通过 FFI 调用 x86_64 Windows 平台下的 C 资源所使用的默认调用约定。</li>
<li><code>extern &quot;sysv64&quot;</code> -- 通过 FFI 调用 非Windows x86_64 平台下的 C 资源所使用的默认调用约定。</li>
<li><code>extern &quot;aapcs&quot;</code> --通过 FFI 调用 ARM 接口所使用的默认调用约定</li>
<li><code>extern &quot;fastcall&quot;</code> -- <code>fastcall</code> ABI——对应于 MSVC 的<code>__fastcall</code> 和 GCC 以及 clang 的 <code>__attribute__((fastcall))</code>。</li>
<li><code>extern &quot;vectorcall&quot;</code> -- <code>vectorcall</code> ABI ——对应于 MSVC 的 <code>__vectorcall</code> 和 clang 的 <code>__attribute__((vectorcall))</code>。</li>
</ul>
<h2><a class="header" href="#variadic-functions" id="variadic-functions">Variadic functions</a></h2>
<h2><a class="header" href="#可变参数函数" id="可变参数函数">可变参数函数</a></h2>
<p>可以在外部块内的函数的参数列表中的一个或多个具名参数后通过引入 <code>...</code> 来让该函数成为可变参数函数。注意可变参数<code>...</code> 前至少有一个具名参数，并且只能位于参数列表的最后。可变参数可以通过标识符来指定：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern &quot;C&quot; {
    fn foo(x: i32, ...);
    fn with_name(format: *const u8, args: ...);
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes-on-extern-blocks" id="attributes-on-extern-blocks">Attributes on extern blocks</a></h2>
<h2><a class="header" href="#外部块上的属性" id="外部块上的属性">外部块上的属性</a></h2>
<p>下面列出的<a href="items/../attributes.html">属性</a>可以控制外部块的行为。</p>
<h3><a class="header" href="#the-link-attribute" id="the-link-attribute">The <code>link</code> attribute</a></h3>
<h3><a class="header" href="#link属性" id="link属性"><code>link</code>属性</a></h3>
<p><em><code>link</code>属性</em>为外部(<code>extern</code>)块中的程序项指定编译器应该链接的本地库的名称。它使用 <a href="items/../attributes.html#meta-item-attribute-syntax"><em>MetaListNameValueStr</em></a>元项属性句法指定其输入参数。<code>name</code>键指定要链接的本地库的名称。<code>kind</code>键是一个可选值，它指定具有以下可选值的库类型：</p>
<ul>
<li><code>dylib</code> — 表示库类型是动态库。如果没有指定 <code>kind</code>，这是默认值。</li>
<li><code>static</code> — 表示库类型是静态库。</li>
<li><code>framework</code> — 表示库类型是 macOS 框架。这只对 macOS 目标平台有效。</li>
</ul>
<p>如果指定了 <code>kind</code>键，则必须指定 <code>name</code>键。</p>
<p>当从主机环境导入 symbols 时，<code>wasm_import_module</code>键可用于为外部(<code>extern</code>)块中的程序项指定 <a href="https://webassembly.github.io/spec/core/syntax/modules.html">WebAssembly模块</a>名称。如果未指定 <code>wasm_import_module</code>，则默认模块名为 <code>env</code>。</p>
<!-- ignore: requires extern linking -->
<pre><code class="language-rust ignore">#[link(name = &quot;crypto&quot;)]
extern {
    // …
}

#[link(name = &quot;CoreFoundation&quot;, kind = &quot;framework&quot;)]
extern {
    // …
}

#[link(wasm_import_module = &quot;foo&quot;)]
extern {
    // …
}
</code></pre>
<p>在空外部块上添加 <code>link</code>属性是有效的。可以用这种方式来满足代码中其他地方的外部块的链接需求（包括上游 crate），而不必向每个外部块都添加此属性。</p>
<h3><a class="header" href="#the-link_name-attribute" id="the-link_name-attribute">The <code>link_name</code> attribute</a></h3>
<h3><a class="header" href="#link_name属性" id="link_name属性"><code>link_name</code>属性</a></h3>
<p>可以在外部(<code>extern</code>)块内的程序项声明上指定 <code>link_name</code>属性，可以用它来指示要为给定函数或静态项导入的具体 symbol。它使用 <a href="items/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法指定 symbol 的名称。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern {
    #[link_name = &quot;actual_symbol_name&quot;]
    fn name_in_rust();
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#attributes-on-function-parameters-1" id="attributes-on-function-parameters-1">Attributes on function parameters</a></h3>
<h3><a class="header" href="#函数参数上的属性-1" id="函数参数上的属性-1">函数参数上的属性</a></h3>
<p>外部函数参数上的属性遵循与<a href="items/functions.html#attributes-on-function-parameters">常规函数参数</a>相同的规则和限制。</p>
<!-- 2021-1-17-->
<!-- checked -->
<h1><a class="header" href="#type-and-lifetime-parameters" id="type-and-lifetime-parameters">Type and Lifetime Parameters</a></h1>
<h1><a class="header" href="#类型参数和生存期参数" id="类型参数和生存期参数">类型参数和生存期参数</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/generics.md">generics.md</a><br />
commit: c0f756e054019646513e9b20f6d4f8193cc0c5b2 <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>GenericParams</em> :<br />
      <code>&lt;</code> <code>&gt;</code><br />
    | <code>&lt;</code> (<em>GenericParam</em> <code>,</code>)<sup>*</sup> <em>GenericParam</em> <code>,</code><sup>?</sup> <code>&gt;</code></p>
<p><em>GenericParam</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> ( <em>LifetimeParam</em> | <em>TypeParam</em> | <em>ConstParam</em> )</p>
<p><em>LifetimeParam</em> :<br />
   <a href="items/../tokens.html#lifetimes-and-loop-labels">LIFETIME_OR_LABEL</a> ( <code>:</code> <a href="items/../trait-bounds.html"><em>LifetimeBounds</em></a> )<sup>?</sup></p>
<p><em>TypeParam</em> :<br />
   <a href="items/../identifiers.html">IDENTIFIER</a>( <code>:</code> <a href="items/../trait-bounds.html"><em>TypeParamBounds</em></a><sup>?</sup> )<sup>?</sup> ( <code>=</code> <a href="items/../types.html#type-expressions"><em>Type</em></a> )<sup>?</sup></p>
<p><em>ConstParam</em>:<br />
   <code>const</code> <a href="items/../identifiers.html">IDENTIFIER</a> <code>:</code> <a href="items/../types.html#type-expressions"><em>Type</em></a></p>
</blockquote>
<p><a href="items/functions.html">函数</a>、<a href="items/type-aliases.html">类型别名</a>、<a href="items/structs.html">结构体</a>、<a href="items/enumerations.html">枚举</a>、<a href="items/unions.html">联合体</a>、<a href="items/traits.html">trait</a> 和<a href="items/implementations.html">实现</a>可以通过类型参数、常量参数和生存期参数达到<em>参数化</em>配置的的效果。这些参数在尖括号<span class="parenthetical">（<code>&lt;...&gt;</code>）</span>中列出，通常都是紧跟在程序项名称之后和程序项的定义之前。对于实现，因为它没有名称，那它们就直接位于关键字 <code>impl</code> 之后。泛型参数的申明顺序是生存期参数在最前面，然后是类型参数，最后是常量参数。</p>
<p>下面给出一些带类型参数、常量参数和生存期参数的程序项的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn foo&lt;'a, T&gt;() {}
trait A&lt;U&gt; {}
struct Ref&lt;'a, T&gt; where T: 'a { r: &amp;'a T }
struct InnerArray&lt;T, const N: usize&gt;([T; N]);
<span class="boring">}
</span></code></pre></pre>
<p>泛型参数在声明它们的程序项定义的范围内有效。它们不是函数体中声明的程序项，这个在<a href="items/../statements.html#item-declarations">程序项声明</a>中有讲述。</p>
<p><a href="items/../types/pointer.html#shared-references-">引用</a>、<a href="items/../types/pointer.html#raw-pointers-const-and-mut">裸指针</a>、<a href="items/../types/array.html">数组</a>、<a href="items/../types/array.html">切片</a>、<a href="items/../types/tuple.html">元组</a>和<a href="items/../types/function-pointer.html">函数指针</a>也有生存期参数或类型参数，但这些程序项不能使用路径句法去引用。</p>
<h3><a class="header" href="#const-generics" id="const-generics">Const generics</a></h3>
<h3><a class="header" href="#常量泛型" id="常量泛型">常量泛型</a></h3>
<p><em>常量泛型参数</em>允许程序项在常量值上泛型化。const标识符为常量参数引入了一个名称，并且该程序项的所有实例必须用给定类型的值去实例化该参数。</p>
<!-- TODO: update above to say "introduces a name in the [value namespace]" once namespaces are added. -->
<p>常量参数类型值允许为：<code>u8</code>, <code>u16</code>, <code>u32</code>, <code>u64</code>, <code>u128</code>, <code>usize</code>, <code>i8</code>, <code>i16</code>, <code>i32</code>, <code>i64</code>, <code>i128</code>, <code>isize</code>, <code>char</code> 和 <code>bool</code> 这些类型。</p>
<p>常量参数可以在任何可以使用<a href="items/constant-items.html">常量项</a>的地方使用，但在<a href="items/../types.html">类型</a>或<a href="items/../expressions/array-expr.html">数组定义中的重复表达式</a>中使用时，必须如下所述是独立的。也就是说，它们可以在以下地方上允许：</p>
<ol>
<li>可以用于类型内部，用它来构成所涉及的程序项签名的一部分。</li>
<li>作为常量表达式的一部分，用于定义<a href="items/associated-items.html#associated-constants">关联常量项</a>，或作为<a href="items/associated-items.html#associated-types">关联类型</a>的形参。</li>
<li>作为程序项里的任何函数体中的任何运行时表达式中的值。</li>
<li>作为程序项中任何函数体中使用到的任何类型的参数。</li>
<li>作为程序项中任何字段类型的一部分使用。</li>
</ol>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 可以使用常量泛型参数的示例。

// 用于程序项本身的签名
fn foo&lt;const N: usize&gt;(arr: [i32; N]) {
    // 在函数体中用作类型。
    let x: [i32; N];
    // 用作表达。
    println!(&quot;{}&quot;, N * 2);
}

// 用作结构体的字段
struct Foo&lt;const N: usize&gt;([i32; N]);

impl&lt;const N: usize&gt; Foo&lt;N&gt; {
    // 用作关联常数
    const CONST: usize = N * 4;
}

trait Trait {
    type Output;
}

impl&lt;const N: usize&gt; Trait for Foo&lt;N&gt; {
    // 用作关联类型
    type Output = [i32; N];
}
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 不能使用常量泛型参数的示例
fn foo&lt;const N: usize&gt;() {
    // 能在函数体中的程序项定义中使用
    const BAD_CONST: [usize; N] = [1; N];
    static BAD_STATIC: [usize; N] = [1; N];
    fn inner(bad_arg: [usize; N]) {
        let bad_value = N * 2;
    }
    type BadAlias = [usize; N];
    struct BadStruct([usize; N]);
}
<span class="boring">}
</span></code></pre></pre>
<p>作为进一步的限制，常量只能作为<a href="items/../types.html">类型</a>或<a href="items/../expressions/array-expr.html">数组定义中的重复表达式</a>中的独立实参出现。在这种上下文限制下，它们只能以单段<a href="items/../expressions/path-expr.html">路径表达式</a>的形式使用（例如 <code>N</code> 或以<a href="items/../expressions/block-expr.html">块</a><code>{N}</code> 的形式出现）。也就是说，它们不能与其他表达式结合使用。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 不能使用常量参数的示例。

// 不允许在类型中的表达式中组合使用，例如这里的返回类型中的算术表达式
fn bad_function&lt;const N: usize&gt;() -&gt; [u8; {N + 1}] {
    // 同样的，这种情况也不允许在数组定义里的重复表达式中使用
    [1; {N + 1}]
}
<span class="boring">}
</span></code></pre></pre>
<p><a href="items/../paths.html">路径</a>中的常量实参指定了该程序项使用的常量值。实参必须是常量形参所属类型的<a href="items/../const_eval.html#constant-expressions">常量表达式</a>。常量表达式必须是<a href="items/../expressions/block-expr.html">块表达式</a>（用花括号括起来），除非它是单独路径段（一个<a href="items/../identifiers.html">标识符</a>）或一个<a href="items/../expressions/literal-expr.html">字面量</a>（此字面量可以是以 <code>-</code> 打头的 token）。</p>
<blockquote>
<p><strong>注意</strong>：这种句法限制是必要的，用以避免在解析类型内部的表达式时可能会导致无限递归(infinite lookahead)。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn double&lt;const N: i32&gt;() {
    println!(&quot;doubled: {}&quot;, N * 2);
}

const SOME_CONST: i32 = 12;

fn example() {
    // 常量参数的使用示例。
    double::&lt;9&gt;();
    double::&lt;-123&gt;();
    double::&lt;{7 + 8}&gt;();
    double::&lt;SOME_CONST&gt;();
    double::&lt;{ SOME_CONST + 5 }&gt;();
}
<span class="boring">}
</span></code></pre></pre>
<p>当存在歧义时，如果泛型参数可以同时被解析为类型或常量参数，那么它总是被解析为类型。在块表达式中放置实参可以强制将其解释为常量实参。</p>
<!-- TODO: Rewrite the paragraph above to be in terms of namespaces, once
    namespaces are introduced, and it is clear which namespace each parameter
    lives in. -->
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>type N = u32;
struct Foo&lt;const N: usize&gt;;
// 下面用法是错误的，因为 `N` 被解释为类型别名。
fn foo&lt;const N: usize&gt;() -&gt; Foo&lt;N&gt; { todo!() } // ERROR
// 可以使用花括号来强制将 `N` 解释为常量形参。
fn bar&lt;const N: usize&gt;() -&gt; Foo&lt;{ N }&gt; { todo!() } // ok
<span class="boring">}
</span></code></pre></pre>
<p>与类型参数和生存期参数不同，常量参数可以声明而不必在被它参数化的程序项中使用，但和<a href="items/implementations.html#generic-implementations">泛型实现</a>关联的实现例外：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// ok
struct Foo&lt;const N: usize&gt;;
enum Bar&lt;const M: usize&gt; { A, B }

// ERROR: 参数未使用
struct Baz&lt;T&gt;;
struct Biz&lt;'a&gt;;
struct Unconstrained;
impl&lt;const N: usize&gt; Unconstrained {}
<span class="boring">}
</span></code></pre></pre>
<p>当处理 trait约束时，在确定是否满足相关约束时，不会考虑常量参数的所有实现的穷尽性。例如，在下面的例子中，即使实现了 <code>bool</code>类型的所有可能的常量值，仍会报错提示 trait约束不满足。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Foo&lt;const B: bool&gt;;
trait Bar {}
impl Bar for Foo&lt;true&gt; {}
impl Bar for Foo&lt;false&gt; {}

fn needs_bar(_: impl Bar) {}
fn generic&lt;const B: bool&gt;() {
    let v = Foo::&lt;B&gt;;
    needs_bar(v); // ERROR: trait约束 `Foo&lt;B&gt;: Bar` 未被满足
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#where-clauses" id="where-clauses">Where clauses</a></h2>
<h2><a class="header" href="#where子句" id="where子句">where子句</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>WhereClause</em> :<br />
   <code>where</code> ( <em>WhereClauseItem</em> <code>,</code> )<sup>*</sup> <em>WhereClauseItem</em> <sup>?</sup></p>
<p><em>WhereClauseItem</em> :<br />
      <em>LifetimeWhereClauseItem</em><br />
   | <em>TypeBoundWhereClauseItem</em></p>
<p><em>LifetimeWhereClauseItem</em> :<br />
   <a href="items/../trait-bounds.html"><em>Lifetime</em></a> <code>:</code> <a href="items/../trait-bounds.html"><em>LifetimeBounds</em></a></p>
<p><em>TypeBoundWhereClauseItem</em> :<br />
   <a href="items/../trait-bounds.html#higher-ranked-trait-bounds"><em>ForLifetimes</em></a><sup>?</sup> <a href="items/../types.html#type-expressions"><em>Type</em></a> <code>:</code> <a href="items/../trait-bounds.html"><em>TypeParamBounds</em></a><sup>?</sup></p>
</blockquote>
<p><em>where子句</em>提供了另一种方法来为类型参数和生存期参数指定约束(bound)，甚至可以为非类型参数的类型指定约束。</p>
<p>关键字<code>for</code> 可以用来引入<a href="items/../trait-bounds.html#higher-ranked-trait-bounds">高阶生存期参数</a>。它只允许在 <a href="items/generics.html#generic-parameters"><em>LifetimeParam</em></a> 参数上使用。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct A&lt;T&gt;
where
    T: Iterator,            // 可以用 A&lt;T: Iterator&gt; 来替代
    T::Item: Copy,          // 在一个关联类型上设置约束
    String: PartialEq&lt;T&gt;,   // 使用类型参数来在字段`String`上设置约束
    i32: Default,           // 允许，但没什么用
{
    f: T,
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes" id="attributes">Attributes</a></h2>
<h2><a class="header" href="#属性" id="属性">属性</a></h2>
<p>泛型生存期参数和泛型类型参数允许<a href="items/../attributes.html">属性</a>，但在目前这个位置还没有任何任何有意义的内置属性，但用户可能可以通过自定义的派生属性来设置一些有意义的属性。</p>
<p>下面示例演示如何使用自定义派生属性修改泛型参数的含义。</p>
<!-- ignore: requires proc macro derive -->
<pre><code class="language-rust ignore">// 假设 MyFlexibleClone 的派生项将 `my_flexible_clone` 声明为它可以理解的属性。
#[derive(MyFlexibleClone)]
struct Foo&lt;#[my_flexible_clone(unbounded)] H&gt; {
    a: *const H
}
</code></pre>
<h1><a class="header" href="#associated-items" id="associated-items">Associated Items</a></h1>
<h1><a class="header" href="#关联程序项关联项" id="关联程序项关联项">关联程序项/关联项</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/items/associated-items.md">associated-items.md</a><br />
commit: 4e138b37b49c49bc875b96b859fbe0caea5a82f3 <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>AssociatedItem</em> :<br />
   <a href="items/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> (<br />
         <a href="items/../macros.html#macro-invocation"><em>MacroInvocationSemi</em></a><br />
      | ( <a href="items/../visibility-and-privacy.html"><em>Visibility</em></a><sup>?</sup> ( <a href="items/type-aliases.html"><em>TypeAlias</em></a> | <a href="items/constant-items.html"><em>ConstantItem</em></a> | <a href="items/functions.html"><em>Function</em></a> ) )<br />
   )</p>
</blockquote>
<p><em>关联程序项</em>是在 <a href="items/traits.html">traits</a> 中声明或在<a href="items/implementations.html">实现</a>中定义的程序项。之所以这样称呼它们，是因为它们是被定义在一个相关联的类型（即实现里指定的类型）上的。关联程序项是那些可在模块中声明的程序项的子集。具体来说，有[关联函数][associated functions]（包括方法）、[关联类型][associated types]和[关联常量][associated constants]。</p>
<p>当关联程序项与被关联程序项在逻辑上相关时，关联程序项就非常有用。例如，<code>Option</code> 上的 <code>is_some</code> 方法内在逻辑定义上就与 Option枚举类型相关，所以它应该和 Option 关联在一起。</p>
<p>每个关联程序项都有两种形式：（包含实际实现的）定义和（为定义声明签名的）声明。<sup class="footnote-reference"><a href="#译者备注1">1</a></sup></p>
<p>正是这些声明构成了 trait 的契约(contract)以及其泛型参数中的可用内容。</p>
<h2><a class="header" href="#associated-functions-and-methods" id="associated-functions-and-methods">Associated functions and methods</a></h2>
<h2><a class="header" href="#关联函数和方法" id="关联函数和方法">关联函数和方法</a></h2>
<p><em>关联函数</em>是与一个类型相关联的<a href="items/functions.html">函数</a>。</p>
<p><em>关联函数声明</em>为<em>关联函数定义</em>声明签名。它的书写格式和函数项一样，除了函数体被替换为 <code>;</code>。</p>
<p>标识符是关联函数的名称。关联函数的泛型参数、参数列表、返回类型 和 where子句必须与它们在<em>关联函数声明</em>中声明的格式一致。</p>
<p><em>关联函数定义</em>定义与另一个类型相关联的函数。它的编写方式与<a href="items/../types/function-item.html">函数项</a>相同。</p>
<p>常见的关联函数的一个例子是 <code>new</code>函数，它返回此关联函数所关联的类型的值。</p>
<pre><pre class="playground"><code class="language-rust edition2018">struct Struct {
    field: i32
}

impl Struct {
    fn new() -&gt; Struct {
        Struct {
            field: 0i32
        }
    }
}

fn main () {
    let _struct = Struct::new();
}
</code></pre></pre>
<p>当关联函数在 trait 上声明时，此函数也可以通过一个指向 trait，再后跟函数名的<a href="items/../paths.html">路径</a>来调用。当发生这种情况时，可以用 trait 的实际路径和关联函数的标识符按 <code>&lt;_ as Trait&gt;::function_name</code> 这样的形式来组织实际的调用路径。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Num {
    fn from_i32(n: i32) -&gt; Self;
}

impl Num for f64 {
    fn from_i32(n: i32) -&gt; f64 { n as f64 }
}

// 在这个案例中，这4种形式都是等价的。
let _: f64 = Num::from_i32(42);
let _: f64 = &lt;_ as Num&gt;::from_i32(42);
let _: f64 = &lt;f64 as Num&gt;::from_i32(42);
let _: f64 = f64::from_i32(42);
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#methods" id="methods">Methods</a></h3>
<h3><a class="header" href="#方法" id="方法">方法</a></h3>
<p>如果关联函数的参数列表中的第一个参数名为 <code>self</code><sup class="footnote-reference"><a href="#译者备注2">2</a></sup>，则此关联函数被称为<em>方法</em>，方法可以使用<a href="items/../expressions/method-call-expr.html">方法调用操作符</a>(<code>.</code>)来调用，例如 <code>x.foo()</code>，也可以使用常用的函数调用形式进行调用。</p>
<p>如果名为 <code>self</code> 的参数的类型被指定了，它就通过以下文法（其中 <code>'lt</code> 表示生存期参数）来把此指定的参数限制解析成此文法中的一个类型：</p>
<pre><code class="language-text">P = &amp;'lt S | &amp;'lt mut S | Box&lt;S&gt; | Rc&lt;S&gt; | Arc&lt;S&gt; | Pin&lt;P&gt;
S = Self | P
</code></pre>
<p>此文法中的 <code>Self</code>终结符(terminal)表示解析为实现类型(implementing type)的类型。这种解析包括解析上下文中的类型别名 <code>Self</code>、其他类型别名、或使用投射解析把（self 的类型中的）关联类型解析为实现类型。<sup class="footnote-reference"><a href="#译者备注3">3</a></sup></p>
<blockquote>
<p>译者注：原谅译者对上面这句背后知识的模糊理解，那首先给出原文：<br />
The <code>Self</code> terminal in this grammar denotes a type resolving to the implementing type. This can also include the contextual type alias <code>Self</code>, other type aliases, or associated type projections resolving to the implementing type. <br />
译者在此先邀请读者中的高手帮忙翻译清楚。感谢感谢。另外译者还是要啰嗦以下译者对这句话背后知识的理解，希望有人能指出其中的错误，以让译者有机会进步：<br />
首先终结符(terminal)就是不能再更细分的词法单元，可以理解它是一个 token，这里它代表 self（即方法接受者）的类型的基础类型。上面句法中的 P 代表一个产生式，它内部定义的规则是并联的，就是自动机在应用这个产生式时碰到任意符合条件的输入就直接进入终态。S 代表有限自动机从 S 这里开始读取 self 的类型。这里 S 是 Self 和 P 的并联，应该表示是：如果 self 的类型直接是 Self，那就直接进入终态，即返回 Self，即方法接收者的直接类型就是结果类型；如果 self 的类型是 P 中的任一种，就返回那一种，比如 self 的类型是一个 box指针，那么就返回 <code>Box&lt;S&gt;</code>。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::rc::Rc;
</span><span class="boring">use std::sync::Arc;
</span><span class="boring">use std::pin::Pin;
</span>// 结构体 `Example` 上的方法示例
struct Example;
type Alias = Example;
trait Trait { type Output; }
impl Trait for Example { type Output = Example; }
impl Example {
    fn by_value(self: Self) {}
    fn by_ref(self: &amp;Self) {}
    fn by_ref_mut(self: &amp;mut Self) {}
    fn by_box(self: Box&lt;Self&gt;) {}
    fn by_rc(self: Rc&lt;Self&gt;) {}
    fn by_arc(self: Arc&lt;Self&gt;) {}
    fn by_pin(self: Pin&lt;&amp;Self&gt;) {}
    fn explicit_type(self: Arc&lt;Example&gt;) {}
    fn with_lifetime&lt;'a&gt;(self: &amp;'a Self) {}
    fn nested&lt;'a&gt;(self: &amp;mut &amp;'a Arc&lt;Rc&lt;Box&lt;Alias&gt;&gt;&gt;) {}
    fn via_projection(self: &lt;Example as Trait&gt;::Output) {}
}
<span class="boring">}
</span></code></pre></pre>
<p>（方法的首参）可以在不指定类型的情况下使用简写句法，具体对比如下：</p>
<table><thead><tr><th>简写模式</th><th>等效项</th></tr></thead><tbody>
<tr><td><code>self</code></td><td><code>self: Self</code></td></tr>
<tr><td><code>&amp;'lifetime self</code></td><td><code>self: &amp;'lifetime Self</code></td></tr>
<tr><td><code>&amp;'lifetime mut self</code></td><td><code>self: &amp;'lifetime mut Self</code></td></tr>
</tbody></table>
<blockquote>
<p><strong>注意</strong>: （方法的）生存期也能，其实也经常是使用这种方式来省略。</p>
</blockquote>
<p>如果 <code>self</code> 参数以 <code>mut</code> 为前缀，它就变成了一个可变的变量，类似于使用 <code>mut</code> <a href="items/../patterns.html#identifier-patterns">标识符模式</a>的常规参数。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Changer: Sized {
    fn change(mut self) {}
    fn modify(mut self: Box&lt;Self&gt;) {}
}
<span class="boring">}
</span></code></pre></pre>
<p>以下是一个关于 trait 的方法的例子，现给定如下内容：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">type Surface = i32;
</span><span class="boring">type BoundingBox = i32;
</span>trait Shape {
    fn draw(&amp;self, surface: Surface);
    fn bounding_box(&amp;self) -&gt; BoundingBox;
}
<span class="boring">}
</span></code></pre></pre>
<p>这里定义了一个带有两个方法的 trait。当此 trait 被引入当前作用域内后，所有此 trait 的<a href="items/implementations.html">实现</a>的值都可以调用此 trait 的 <code>draw</code> 和 <code>bounding_box</code> 方法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">type Surface = i32;
</span><span class="boring">type BoundingBox = i32;
</span><span class="boring">trait Shape {
</span><span class="boring">    fn draw(&amp;self, surface: Surface);
</span><span class="boring">    fn bounding_box(&amp;self) -&gt; BoundingBox;
</span><span class="boring">}
</span><span class="boring">
</span>struct Circle {
    // ...
}

impl Shape for Circle {
    // ...
<span class="boring">  fn draw(&amp;self, _: Surface) {}
</span><span class="boring">  fn bounding_box(&amp;self) -&gt; BoundingBox { 0i32 }
</span>}

<span class="boring">impl Circle {
</span><span class="boring">    fn new() -&gt; Circle { Circle{} }
</span><span class="boring">}
</span><span class="boring">
</span>let circle_shape = Circle::new();
let bounding_box = circle_shape.bounding_box();
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><strong>版本差异</strong>: 在 2015 版中, 使用匿名参数来声明 trait方法是可能的 (例如：<code>fn foo(u8)</code>)。在 2018 版本中，这已被弃用，再用会导致编译错误。新版本种所有的参数都必须有参数名。</p>
</blockquote>
<h4><a class="header" href="#attributes-on-method-parameters" id="attributes-on-method-parameters">Attributes on method parameters</a></h4>
<h4><a class="header" href="#方法参数上的属性" id="方法参数上的属性">方法参数上的属性</a></h4>
<p>方法参数上的属性遵循与<a href="items/functions.html#attributes-on-function-parameters">常规函数参数</a>上相同的规则和限制。</p>
<h2><a class="header" href="#associated-types" id="associated-types">Associated Types</a></h2>
<h2><a class="header" href="#关联类型" id="关联类型">关联类型</a></h2>
<p><em>关联类型</em>是与另一个类型关联的<a href="items/type-aliases.html">类型别名(type aliases)</a> 。关联类型不能在<a href="items/implementations.html#inherent-implementations">固有实现</a>中定义，也不能在 trait 中给它们一个默认实现。</p>
<p><em>关联类型声明</em>为<em>关联类型定义</em>声明签名。书写形式为：先是 <code>type</code>，然后是一个<a href="items/../identifiers.html">标识符</a>，最后是一个可选的 trait约束列表。</p>
<p>这里的标识符是声明的类型的别名名称；其可选的 trait约束必须由此类型别名的实现(implementations)来履行实现。
关联类型上有一个隐式的 <a href="items/../special-types-and-traits.html#sized"><code>Sized</code></a>约束，可以使用 <code>？Sized</code>放宽此约束。</p>
<p><em>关联类型定义</em>在另一个类型上定义了一个类型别名。书写形式为：先是 <code>type</code>，然后是一个[标识符]，然后再是一个 <code>=</code>，最后是一个<a href="items/../types.html#type-expressions">类型</a>。</p>
<p>如果类型 <code>Item</code> 上有一个来自 trait <code>Trait</code>的关联类型 <code>Assoc</code>，则表达式 <code>&lt;Item as Trait&gt;::Assoc</code> 也是一个类型，具体就是<em>关联类型定义</em>中指定的类型的一个别名。此外，如果 <code>Item</code> 是类型参数，则 <code>Item::Assoc</code> 也可以在类型参数中使用。</p>
<p>关联类型不能包括<a href="items/generics.html">泛型参数</a>或 <a href="items/generics.html#where-clauses">where子句</a>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">trait AssociatedType {
    // 关联类型声明
    type Assoc;
}

struct Struct;

struct OtherStruct;

impl AssociatedType for Struct {
    // 关联类型定义
    type Assoc = OtherStruct;
}

impl OtherStruct {
    fn new() -&gt; OtherStruct {
        OtherStruct
    }
}

fn main() {
    // 使用 &lt;Struct as AssociatedType&gt;::Assoc 来引用关联类型 OtherStruct
    let _other_struct: OtherStruct = &lt;Struct as AssociatedType&gt;::Assoc::new();
}
</code></pre></pre>
<h3><a class="header" href="#associated-types-container-example" id="associated-types-container-example">Associated Types Container Example</a></h3>
<h3><a class="header" href="#示例展示容器内的关联类型" id="示例展示容器内的关联类型">示例展示容器内的关联类型</a></h3>
<p>下面给出一个 <code>Container</code> trait 示例。请注意，该类型可用在方法签名内：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Container {
    type E;
    fn empty() -&gt; Self;
    fn insert(&amp;mut self, elem: Self::E);
}
<span class="boring">}
</span></code></pre></pre>
<p>为了能让实现类型来实现此 trait，实现类型不仅必须为每个方法提供实现，而且必须指定类型 <code>E</code>。下面是一个为标准库类型 <code>Vec</code> 实现了此 <code>Container</code> 的实现：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait Container {
</span><span class="boring">    type E;
</span><span class="boring">    fn empty() -&gt; Self;
</span><span class="boring">    fn insert(&amp;mut self, elem: Self::E);
</span><span class="boring">}
</span>impl&lt;T&gt; Container for Vec&lt;T&gt; {
    type E = T;
    fn empty() -&gt; Vec&lt;T&gt; { Vec::new() }
    fn insert(&amp;mut self, x: T) { self.push(x); }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#associated-constants" id="associated-constants">Associated Constants</a></h2>
<h2><a class="header" href="#关联常量" id="关联常量">关联常量</a></h2>
<p><em>关联常量</em>是与具体类型关联的<a href="items/constant-items.html">常量</a>。</p>
<p><em>关联常量声明</em>为<em>关联常量定义</em>声明签名。书写形式为：先是 <code>const</code> 开头，然后是标识符，然后是 <code>:</code>，然后是一个类型，最后是一个 <code>;</code>。</p>
<p>这里标识符是（外部引用）路径中使用的常量的名称；类型是（此关联常量的）定义必须实现的类型。</p>
<p><em>关联常量定义</em>定义了与类型关联的常量。它的书写方式与<a href="items/constant-items.html">常量项</a>相同。</p>
<h3><a class="header" href="#associated-constants-examples" id="associated-constants-examples">Associated Constants Examples</a></h3>
<h3><a class="header" href="#示例展示关联常量" id="示例展示关联常量">示例展示关联常量</a></h3>
<p>基本示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">trait ConstantId {
    const ID: i32;
}

struct Struct;

impl ConstantId for Struct {
    const ID: i32 = 1;
}

fn main() {
    assert_eq!(1, Struct::ID);
}
</code></pre></pre>
<p>使用默认值：</p>
<pre><pre class="playground"><code class="language-rust edition2018">trait ConstantIdDefault {
    const ID: i32 = 1;
}

struct Struct;
struct OtherStruct;

impl ConstantIdDefault for Struct {}

impl ConstantIdDefault for OtherStruct {
    const ID: i32 = 5;
}

fn main() {
    assert_eq!(1, Struct::ID);
    assert_eq!(5, OtherStruct::ID);
}
</code></pre></pre>
<div class="footnote-definition" id="译者备注1"><sup class="footnote-definition-label">1</sup>
<p>固有实现中声明和定义是在一起的。</p>
</div>
<div class="footnote-definition" id="译者备注2"><sup class="footnote-definition-label">2</sup>
<p>把简写形式转换成等价的标准形式。</p>
</div>
<div class="footnote-definition" id="译者备注3"><sup class="footnote-definition-label">3</sup>
<p>结合下面的示例理解。</p>
</div>
<script>
(function() {
    var fragments = {
        "#cold-attribute": "attributes/codegen.html#the-cold-attribute",
        "#conditional-compilation": "conditional-compilation.html",
        "#deprecation": "attributes/diagnostics.html#the-deprecated-attribute",
        "#derive": "attributes/derive.html",
        "#documentation": "https://doc.rust-lang.org/rustdoc/the-doc-attribute.html",
        "#ffi-attributes": "attributes.html#built-in-attributes-index",
        "#inline-attribute": "attributes/codegen.html#the-inline-attribute",
        "#lint-check-attributes": "attributes/diagnostics.html#lint-check-attributes",
        "#macro-related-attributes": "attributes.html#built-in-attributes-index",
        "#miscellaneous-attributes": "attributes.html#built-in-attributes-index",
        "#must_use": "attributes/diagnostics.html#the-must_use-attribute",
        "#optimization-hints": "attributes/codegen.html#optimization-hints",
        "#path": "items/modules.html#the-path-attribute",
        "#preludes": "crates-and-source-files.html#preludes-and-no_std",
        "#testing": "attributes/testing.html",
        "#tool-lint-attributes": "attributes/diagnostics.html#tool-lint-attributes",
        "#crate-only-attributes": "attributes.html#built-in-attributes-index",
    };
    var target = fragments[window.location.hash];
    if (target) {
        var url = window.location.toString();
        var base = url.substring(0, url.lastIndexOf('/'));
        window.location.replace(base + "/" + target);
    }
})();
</script>
<h1><a class="header" href="#attributes-1" id="attributes-1">Attributes</a></h1>
<h1><a class="header" href="#属性-1" id="属性-1">属性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes.md">attributes.md</a><br />
commit: efb2c1cab0302a985030a94adafae9e630a7894d <br />
本章译文最后维护日期：2021-5-29</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>InnerAttribute</em> :<br />
   <code>#</code> <code>!</code> <code>[</code> <em>Attr</em> <code>]</code></p>
<p><em>OuterAttribute</em> :<br />
   <code>#</code> <code>[</code> <em>Attr</em> <code>]</code></p>
<p><em>Attr</em> :<br />
   <a href="paths.html#simple-paths"><em>SimplePath</em></a> <em>AttrInput</em><sup>?</sup></p>
<p><em>AttrInput</em> :<br />
      <a href="macros.html"><em>DelimTokenTree</em></a><br />
   | <code>=</code> <a href="expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>属性</em>是一种通用的、格式自由的元数据(free-form metadatum)，这种元数据会（被编译器/解释器）依据名称、约定、语言和编译器版本进行解释。（Rust 语言中的）属性是根据 <a href="https://www.ecma-international.org/publications/standards/Ecma-335.htm">ECMA-335</a> 标准中的属性规范进行建模的，其语法来自 <a href="https://www.ecma-international.org/publications/standards/Ecma-334.htm">ECMA-334</a> (C#）。</p>
<p>*内部属性(Inner attributes)*以 <code>#!</code> 开头的方式编写，应用于它在其中声明的程序项。*外部属性(Outer attributes)*以不后跟感叹号的(<code>!</code>)的 <code>#</code> 开头的方式编写，应用于属性后面的内容。</p>
<p>属性由指向属性的路径和路径后跟的可选的带定界符的 token树(delimited token tree)（其解释由属性定义）组成。除了宏属性之外，其他属性的输入也允许使用等号(<code>=</code>)后跟表达式的格式。更多细节请参见下面的<a href="attributes.html#meta-item-attribute-syntax">元项属性句法(meta item syntax)</a>。</p>
<p>属性可以分为以下几类：</p>
<ul>
<li><a href="attributes.html#built-in-attributes-index">内置属性</a></li>
<li><a href="procedural-macros.html#attribute-macros">宏属性</a></li>
<li><a href="procedural-macros.html#derive-macro-helper-attributes">派生宏辅助属性</a></li>
<li><a href="attributes.html#tool-attributes">外部工具属性</a></li>
</ul>
<p>属性可以应用于语言中的许多场景：</p>
<ul>
<li>所有的<a href="items.html">程序项声明</a>都可接受外部属性，同时<a href="items/external-blocks.html">外部块</a>、<a href="items/functions.html">函数</a>、<a href="items/implementations.html">实现</a>和<a href="items/modules.html">模块</a>都可接受内部属性。</li>
<li>大多数<a href="statements.html">语句</a>都可接受外部属性（参见<a href="expressions.html#expression-attributes">表达式属性</a>，了解表达式语句的限制）。</li>
<li><a href="expressions/block-expr.html">块表达式</a>也可接受外部属性和内部属性，但只有当它们是另一个<a href="statements.html#expression-statements">表达式语句</a>的外层表达式时，或是另一个块表达式的最终表达式(final expression)时才有效。</li>
<li><a href="items/enumerations.html">枚举(<code>enum</code>)</a>变体和<a href="items/structs.html">结构体(<code>struct</code>)</a>、<a href="items/unions.html">联合体(<code>union</code>)</a>的字段可接受外部属性。</li>
<li><a href="expressions/match-expr.html">匹配表达式的匹配臂(arms)</a>可接受外部属性。</li>
<li><a href="items/generics.html">泛型生存期(Generic lifetime)或类型参数</a>可接受外部属性。</li>
<li>表达式在有限的情况下可接受外部属性，详见<a href="expressions.html#expression-attributes">表达式属性</a>。</li>
<li><a href="items/functions.html">函数</a>、<a href="expressions/closure-expr.html">闭包</a>和<a href="types/function-pointer.html">函数指针</a>的参数可接受外部属性。这包括函数指针和<a href="items/external-blocks.html#variadic-functions">外部块</a>中用 <code>...</code> 表示的可变参数上的属性。</li>
</ul>
<p>属性的一些例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 应用于当前模块或 crate 的一般性元数据。
#![crate_type = &quot;lib&quot;]

// 标记为单元测试的函数
#[test]
fn test_foo() {
    /* ... */
}

// 一个条件编译模块
#[cfg(target_os = &quot;linux&quot;)]
mod bar {
    /* ... */
}

// 用于静音 lint检查后报告的告警和错误提醒
#[allow(non_camel_case_types)]
type int8_t = i8;

// 适用于整个函数的内部属性
fn some_unused_variables() {
  #![allow(unused_variables)]

  let x = ();
  let y = ();
  let z = ();
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#meta-item-attribute-syntax" id="meta-item-attribute-syntax">Meta Item Attribute Syntax</a></h2>
<h2><a class="header" href="#元项元程序项属性句法" id="元项元程序项属性句法">元项/元程序项属性句法</a></h2>
<p>“元项(meta item)”是遵循 <em>Attr</em> 产生式（见本章头部）的句法，Rust 的大多数<a href="attributes.html#built-in-attributes-index">内置属性(built-in attributes)</a>都使用了此句法。它有以下文法格式：</p>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MetaItem</em> :<br />
      <a href="paths.html#simple-paths"><em>SimplePath</em></a><br />
   | <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>=</code> <a href="expressions.html"><em>Expression</em></a><br />
   | <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>(</code> <em>MetaSeq</em><sup>?</sup> <code>)</code></p>
<p><em>MetaSeq</em> :<br />
   <em>MetaItemInner</em> ( <code>,</code> MetaItemInner )<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>MetaItemInner</em> :<br />
      <em>MetaItem</em><br />
   | <a href="expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>元项中的表达式必须能宏展开为字面量表达式，且字面量表达式不得包含整型或浮点型后缀。现在，非字面量表达式的表达式可以在语法上被接受（并且可以传递给过程宏）了，但在解析后却被丢弃。</p>
<p>请注意，如果该属性出现在另一个宏中，它将在该外部宏展开之后再展开。例如，下面的代码将首先展开为名为 <code>Serialize</code> 的过程宏，在第一次展开时，它必须保留 <code>include_str!</code>调用，以便将来再次展开：</p>
<pre><code class="language-rustignore">#[derive(Serialize)]
struct Foo {
    #[doc = include_str!(&quot;x.md&quot;)]
    x: u32
}
</code></pre>
<p>此外，对与某个程序项来说，如果它的属性中用到了宏，那这个宏仅在所有其他相关属性都展开生效之后才展开：</p>
<pre><code class="language-rustignore">#[macro_attr1] // 展开排序为第一
#[doc = mac!()] // `mac!` 展开排序为第四
#[macro_attr2] // 展开排序为第二
#[derive(MacroDerive1, MacroDerive2)] // 展开排序为第三
fn foo() {}
</code></pre>
<p>各种内置属性使用元项句法的不同子集来指定它们的输入。下面的文法规则展示了一些常用的使用形式：</p>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MetaWord</em>:<br />
   <a href="identifiers.html">IDENTIFIER</a></p>
<p><em>MetaNameValueStr</em>:<br />
   <a href="identifiers.html">IDENTIFIER</a> <code>=</code> (<a href="tokens.html#string-literals">STRING_LITERAL</a> | <a href="tokens.html#raw-string-literals">RAW_STRING_LITERAL</a>)</p>
<p><em>MetaListPaths</em>:<br />
   <a href="identifiers.html">IDENTIFIER</a> <code>(</code> ( <a href="paths.html#simple-paths"><em>SimplePath</em></a> (<code>,</code> <a href="paths.html#simple-paths"><em>SimplePath</em></a>)* <code>,</code><sup>?</sup> )<sup>?</sup> <code>)</code></p>
<p><em>MetaListIdents</em>:<br />
   <a href="identifiers.html">IDENTIFIER</a> <code>(</code> ( <a href="identifiers.html">IDENTIFIER</a> (<code>,</code> <a href="identifiers.html">IDENTIFIER</a>)* <code>,</code><sup>?</sup> )<sup>?</sup> <code>)</code></p>
<p><em>MetaListNameValueStr</em>:<br />
   <a href="identifiers.html">IDENTIFIER</a> <code>(</code> ( <em>MetaNameValueStr</em> (<code>,</code> <em>MetaNameValueStr</em>)* <code>,</code><sup>?</sup> )<sup>?</sup> <code>)</code></p>
</blockquote>
<p>元项句法的一些例子是：</p>
<table><thead><tr><th>形式</th><th>示例</th></tr></thead><tbody>
<tr><td><em>MetaWord</em></td><td><code>no_std</code></td></tr>
<tr><td><em>MetaNameValueStr</em></td><td><code>doc = &quot;example&quot;</code></td></tr>
<tr><td><em>MetaListPaths</em></td><td><code>allow(unused, clippy::inline_always)</code></td></tr>
<tr><td><em>MetaListIdents</em></td><td><code>macro_use(foo, bar)</code></td></tr>
<tr><td><em>MetaListNameValueStr</em></td><td><code>link(name = &quot;CoreFoundation&quot;, kind = &quot;framework&quot;)</code></td></tr>
</tbody></table>
<h2><a class="header" href="#active-and-inert-attributes" id="active-and-inert-attributes">Active and inert attributes</a></h2>
<h2><a class="header" href="#活跃属性和惰性属性" id="活跃属性和惰性属性">活跃属性和惰性属性</a></h2>
<p>属性要么是活跃的，要么是惰性的。在属性处理过程中，<em>活跃属性</em>将自己从它们所在的对象上移除，而<em>惰性属性</em>依然保持原位置不变。</p>
<p><a href="conditional-compilation.html#the-cfg-attribute"><code>cfg</code></a> 和 <a href="conditional-compilation.html#the-cfg_attr-attribute"><code>cfg_attr</code></a> 属性是活跃的。<a href="attributes/testing.html#the-test-attribute"><code>test</code></a>属性在为测试所做的编译形式中是惰性的，在其他编译形式中是活跃的。<a href="procedural-macros.html#attribute-macros">宏属性</a>是活跃的。所有其他属性都是惰性的。</p>
<h2><a class="header" href="#tool-attributes" id="tool-attributes">Tool attributes</a></h2>
<h2><a class="header" href="#外部工具属性" id="外部工具属性">外部工具属性</a></h2>
<p>编译器可能允许和具体外部工具相关联的属性，但这些工具在编译和检查过程中必须存在并驻留在编译器提供的<a href="names/preludes.html#tool-prelude">工具类预导入包</a>下对应的命名空间中（才能让这些属性生效）。这种属性的（命名空间）路径的第一段是工具的名称，后跟一个或多个工具自己解释的附加段。</p>
<p>当工具在编译期不可用时，该工具的属性将被静默接受而不提示警告。当工具可用时，该工具负责处理和解释这些属性。</p>
<p>如果使用了 <a href="names/preludes.html#the-no_implicit_prelude-attribute"><code>no_implicit_prelude</code></a>属性，则外部工具属性不可用。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 告诉rustfmt工具不要格式化以下元素。
#[rustfmt::skip]
struct S {
}

// 控制clippy工具的“圈复杂度(cyclomatic complexity)”极限值。
#[clippy::cyclomatic_complexity = &quot;100&quot;]
pub fn f() {}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意: <code>rustc</code> 目前能识别的工具是 “clippy” 和 “rustfmt”。</p>
</blockquote>
<h2><a class="header" href="#built-in-attributes-index" id="built-in-attributes-index">Built-in attributes index</a></h2>
<h2><a class="header" href="#内置属性的索引表" id="内置属性的索引表">内置属性的索引表</a></h2>
<p>下面是所有内置属性的索引表：</p>
<ul>
<li>条件编译(Conditional compilation)
<ul>
<li><a href="conditional-compilation.html#the-cfg-attribute"><code>cfg</code></a> — 控制条件编译。</li>
<li><a href="conditional-compilation.html#the-cfg_attr-attribute"><code>cfg_attr</code></a> — 选择性包含属性。</li>
</ul>
</li>
<li>测试(Testing)
<ul>
<li><a href="attributes/testing.html#the-test-attribute"><code>test</code></a> — 将函数标记为测试函数。</li>
<li><a href="attributes/testing.html#the-ignore-attribute"><code>ignore</code></a> — 禁止测试此函数。</li>
<li><a href="attributes/testing.html#the-should_panic-attribute"><code>should_panic</code></a> — 表示测试应该产生 panic。</li>
</ul>
</li>
<li>派生(Derive)
<ul>
<li><a href="attributes/derive.html"><code>derive</code></a> — 自动部署 trait实现</li>
<li><a href="attributes/derive.html#the-automatically_derived-attribute"><code>automatically_derived</code></a> — 用在由 <code>derive</code> 创建的实现上的标记。</li>
</ul>
</li>
<li>宏(Macros)
<ul>
<li><a href="macros-by-example.html#path-based-scope"><code>macro_export</code></a> — 导出声明宏（<code>macro_rules</code>宏），用于跨 crate 的使用。</li>
<li><a href="macros-by-example.html#the-macro_use-attribute"><code>macro_use</code></a> — 扩展宏可见性，或从其他 crate 导入宏。</li>
<li><a href="procedural-macros.html#function-like-procedural-macros"><code>proc_macro</code></a> — 定义类函数宏。</li>
<li><a href="procedural-macros.html#derive-macros"><code>proc_macro_derive</code></a> — 定义派生宏。</li>
<li><a href="procedural-macros.html#attribute-macros"><code>proc_macro_attribute</code></a> — 定义属性宏。</li>
</ul>
</li>
<li>诊断(Diagnostics)
<ul>
<li><a href="attributes/diagnostics.html#lint-check-attributes"><code>allow</code></a>、<a href="attributes/diagnostics.html#lint-check-attributes"><code>warn</code></a>、<a href="attributes/diagnostics.html#lint-check-attributes"><code>deny</code></a>、<a href="attributes/diagnostics.html#lint-check-attributes"><code>forbid</code></a> — 更改默认的 lint检查级别。</li>
<li><a href="attributes/diagnostics.html#the-deprecated-attribute"><code>deprecated</code></a> — 生成弃用通知。</li>
<li><a href="attributes/diagnostics.html#the-must_use-attribute"><code>must_use</code></a> — 为未使用的值生成 lint 提醒。</li>
</ul>
</li>
<li>ABI、链接(linking)、符号(symbol)、和 FFI
<ul>
<li><a href="items/external-blocks.html#the-link-attribute"><code>link</code></a> — 指定要与外部(<code>extern</code>)块链接的本地库。</li>
<li><a href="items/external-blocks.html#the-link_name-attribute"><code>link_name</code></a> — 指定外部(<code>extern</code>)块中的函数或静态项的符号(symbol)名。</li>
<li><a href="items/extern-crates.html#the-no_link-attribute"><code>no_link</code></a> — 防止链接外部crate。</li>
<li><a href="type-layout.html#representations"><code>repr</code></a> — 控制类型的布局。</li>
<li><a href="linkage.html"><code>crate_type</code></a> — 指定 crate 的类别(库、可执行文件等)。</li>
<li><a href="crates-and-source-files.html#the-no_main-attribute"><code>no_main</code></a> — 禁止发布 <code>main</code>符号(symbol)。</li>
<li><a href="abi.html#the-export_name-attribute"><code>export_name</code></a> — 指定函数或静态项导出的符号(symbol)名。</li>
<li><a href="abi.html#the-link_section-attribute"><code>link_section</code></a> — 指定用于函数或静态项的对象文件的部分。</li>
<li><a href="abi.html#the-no_mangle-attribute"><code>no_mangle</code></a> — 禁用对符号(symbol)名编码。</li>
<li><a href="abi.html#the-used-attribute"><code>used</code></a> — 强制编译器在输出对象文件中保留静态项。</li>
<li><a href="crates-and-source-files.html#the-crate_name-attribute"><code>crate_name</code></a> — 指定 crate名。</li>
</ul>
</li>
<li>代码生成(Code generation)
<ul>
<li><a href="attributes/codegen.html#the-inline-attribute"><code>inline</code></a> — 内联代码提示。</li>
<li><a href="attributes/codegen.html#the-cold-attribute"><code>cold</code></a> — 提示函数不太可能被调用。</li>
<li><a href="attributes/codegen.html#the-no_builtins-attribute"><code>no_builtins</code></a> — 禁用某些内置函数。</li>
<li><a href="attributes/codegen.html#the-target_feature-attribute"><code>target_feature</code></a> — 配置特定于平台的代码生成。</li>
<li><a href="attributes/codegen.html#the-track_caller-attribute"><code>track_caller</code></a> - 将父调用位置传递给 <code>std::panic::Location::caller()</code>。</li>
</ul>
</li>
<li>文档(Documentation)
<ul>
<li><code>doc</code> — 指定文档。更多信息见 <a href="https://doc.rust-lang.org/rustdoc/the-doc-attribute.html">The Rustdoc Book</a>。<a href="comments.html#doc-comments">Doc注释</a>会被转换为 <code>doc</code>属性。</li>
</ul>
</li>
<li>预导入包(Preludes)
<ul>
<li><a href="names/preludes.html#the-no_std-attribute"><code>no_std</code></a> — 从预导入包中移除 std。</li>
<li><a href="names/preludes.html#the-no_implicit_prelude-attribute"><code>no_implicit_prelude</code></a> — 禁用模块内的预导入包查找。</li>
</ul>
</li>
<li>模块(Modules)
<ul>
<li><a href="items/modules.html#the-path-attribute"><code>path</code></a> — 指定模块的源文件名。</li>
</ul>
</li>
<li>极限值设置(Limits)
<ul>
<li><a href="attributes/limits.html#the-recursion_limit-attribute"><code>recursion_limit</code></a> — 设置某些编译时操作的最大递归限制。</li>
<li><a href="attributes/limits.html#the-type_length_limit-attribute"><code>type_length_limit</code></a> — 设置多态类型(polymorphic type)单态化过程中构造具体类型时所做的最大类型替换次数。</li>
</ul>
</li>
<li>运行时(Runtime)
<ul>
<li><a href="runtime.html#the-panic_handler-attribute"><code>panic_handler</code></a> — 设置处理 panic 的函数。</li>
<li><a href="runtime.html#the-global_allocator-attribute"><code>global_allocator</code></a> — 设置全局内存分配器。</li>
<li><a href="runtime.html#the-windows_subsystem-attribute"><code>windows_subsystem</code></a> — 指定要链接的 windows 子系统。</li>
</ul>
</li>
<li>特性(Features)
<ul>
<li><code>feature</code> — 用于启用非稳定的或实验性的编译器特性。参见 <a href="https://doc.rust-lang.org/unstable-book/index.html">The Unstable Book</a> 了解在 <code>rustc</code> 中实现的特性。</li>
</ul>
</li>
<li>类型系统(Type System)
<ul>
<li><a href="attributes/type_system.html#the-non_exhaustive-attribute"><code>non_exhaustive</code></a> — 表明一个类型将来会添加更多的字段/变体。</li>
</ul>
</li>
</ul>
<h1><a class="header" href="#testing-attributes" id="testing-attributes">Testing attributes</a></h1>
<h1><a class="header" href="#测试类属性" id="测试类属性">测试类属性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/testing.md">testing.md</a><br />
commit: b0e0ad6490d6517c19546b1023948986578fc378 <br />
本章译文最后维护日期：2020-11-10</p>
</blockquote>
<p>以下<a href="attributes/../attributes.html">属性</a>用于指定函数来执行测试。在“测试(test)”模式下编译 crate 可以构建测试函数以及构建用于执行测试（函数）的测试套件(test harness)。启用测试模式还会启用 <a href="attributes/../conditional-compilation.html#test"><code>test</code>条件编译选项</a>。</p>
<h2><a class="header" href="#the-test-attribute" id="the-test-attribute">The <code>test</code> attribute</a></h2>
<h2><a class="header" href="#test属性" id="test属性"><code>test</code>属性</a></h2>
<p><em><code>test</code>属性</em>标记一个用来执行测试的函数。这些函数只在测试模式下编译。测试函数必须是自由函数和单态函数，不能有参数，返回类型必须是以下类型之一：</p>
<ul>
<li><code>()</code></li>
<li><code>Result&lt;(), E&gt; where E: Error</code></li>
</ul>
<!-- * `!` -->
<!-- * Result<!, E> where E: Error` -->
<blockquote>
<p>注意：允许哪些返回类型是由暂未稳定的 <a href="https://doc.rust-lang.org/std/process/trait.Termination.html"><code>Termination</code></a> trait 决定的。</p>
</blockquote>
<!-- 如果前面这节需要更新(从 "不能有参数" 开始, 同时需要修改 crates-and-source-files.md 文件 -->
<blockquote>
<p>注意：测试模式是通过将 <code>--test</code> 参数选项传递给 <code>rustc</code> 或使用 <code>cargo test</code> 来启用的。</p>
</blockquote>
<p>返回 <code>()</code> 的测试只要结束(terminate)且没有触发 panic 就会通过。返回 <code>Result&lt;(), E&gt;</code> 的测试只要它们返回 <code>Ok(())</code> 就算通过。不结束的测试既不（计为）通过也不（计为）失败。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::io;
</span><span class="boring">fn setup_the_thing() -&gt; io::Result&lt;i32&gt; { Ok(1) }
</span><span class="boring">fn do_the_thing(s: &amp;i32) -&gt; io::Result&lt;()&gt; { Ok(()) }
</span>#[test]
fn test_the_thing() -&gt; io::Result&lt;()&gt; {
    let state = setup_the_thing()?; // 预期成功
    do_the_thing(&amp;state)?;          // 预期成功
    Ok(())
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#the-ignore-attribute" id="the-ignore-attribute">The <code>ignore</code> attribute</a></h2>
<h2><a class="header" href="#ignore属性" id="ignore属性"><code>ignore</code>属性</a></h2>
<p>被 <code>test</code>属性标注的(annotated with)函数也可以被 <code>ignore</code>属性标注。<em><code>ignore</code>属性</em>告诉测试套件不要将该函数作为测试执行。但在测试模式下，这类函数仍然会被编译。</p>
<p><code>ignore</code>属性可以选择使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法来说明测试被忽略的原因。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[test]
#[ignore = &quot;not yet implemented&quot;]
fn mytest() {
    // …
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><strong>注意</strong>：<code>rustc</code> 的测试套件支持使用 <code>--include-ignored</code> 参数选项来强制运行那些被忽略测试的函数。</p>
</blockquote>
<h2><a class="header" href="#the-should_panic-attribute" id="the-should_panic-attribute">The <code>should_panic</code> attribute</a></h2>
<h2><a class="header" href="#should_panic属性" id="should_panic属性"><code>should_panic</code>属性</a></h2>
<p>被 <code>test</code>属性标注并返回 <code>()</code> 的函数也可以被 <code>should_panic</code>属性标注。<em><code>should_panic</code>属性</em>使测试函数只有在实际发生 panic 时才算通过。</p>
<p><code>should_panic</code>属性可选输入一条出现在 panic消息中的字符串。如果在 panic消息中找不到该字符串，则测试将失败。可以使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法或带有 <code>expected</code>字段的 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaListNameValueStr</em></a>元项属性句法来传递字符串。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[test]
#[should_panic(expected = &quot;值未匹配上&quot;)]
fn mytest() {
    assert_eq!(1, 2, &quot;值未匹配上&quot;);
}
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#derive" id="derive">Derive</a></h1>
<h1><a class="header" href="#派生" id="派生">派生</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/derive.md">derive.md</a><br />
commit: a52543267554541a95088b79f46a8bd36f487603 <br />
本章译文最后维护日期：2020-11-10</p>
</blockquote>
<p><em><code>derive</code>属性</em>允许为数据结构自动生成新的<a href="attributes/../items.html">程序项</a>。它使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaListPaths</em></a>元项属性句法（为程序项）指定一系列要实现的 trait 或指定要执行的<a href="attributes/../procedural-macros.html#derive-macros">派生宏</a>的路径。</p>
<p>例如，下面的派生属性将为结构体 <code>Foo</code> 创建一个实现 <a href="https://doc.rust-lang.org/std/cmp/trait.PartialEq.html"><code>PartialEq</code></a> trait 和 <a href="https://doc.rust-lang.org/std/clone/trait.Clone.html"><code>Clone</code></a> trait 的<a href="attributes/../items/implementations.html">实现(<code>impl</code> item)</a>，类型参数 <code>T</code> 将被派生出的实现(<code>impl</code>)加上 <code>PartialEq</code> 或<sup class="footnote-reference"><a href="#or-and">1</a></sup> <code>Clone</code> 约束：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[derive(PartialEq, Clone)]
struct Foo&lt;T&gt; {
    a: i32,
    b: T,
}
<span class="boring">}
</span></code></pre></pre>
<p>上面代码为 <code>PartialEq</code> 生成的实现(<code>impl</code>)等价于</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Foo&lt;T&gt; { a: i32, b: T }
</span>impl&lt;T: PartialEq&gt; PartialEq for Foo&lt;T&gt; {
    fn eq(&amp;self, other: &amp;Foo&lt;T&gt;) -&gt; bool {
        self.a == other.a &amp;&amp; self.b == other.b
    }

    fn ne(&amp;self, other: &amp;Foo&lt;T&gt;) -&gt; bool {
        self.a != other.a || self.b != other.b
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>可以通过<a href="attributes/../procedural-macros.html#derive-macros">过程宏</a>为自定义的 trait 实现自动派生(<code>derive</code>)功能。</p>
<h2><a class="header" href="#the-automatically_derived-attribute" id="the-automatically_derived-attribute">The <code>automatically_derived</code> attribute</a></h2>
<h2><a class="header" href="#automatically_derived属性" id="automatically_derived属性"><code>automatically_derived</code>属性</a></h2>
<p><em><code>automatically_derived</code>属性</em>会被自动添加到由 <code>derive</code>属性为一些内置trait 自动派生的<a href="attributes/../items/implementations.html">实现</a>中。它对派生出的实现没有直接影响，但是工具和诊断lint 可以使用它来检测这些自动派生的实现。</p>
<div class="footnote-definition" id="or-and"><sup class="footnote-definition-label">1</sup>
<p>原文后半句是：&quot;and the type parameter <code>T</code> will be given the <code>PartialEq</code> or <code>Clone</code> constraints for the appropriate <code>impl</code>:&quot;，这里译者也搞不清楚为什么 <code>PartialEq</code> 和 <code>Clone</code> 之间用了&quot;or&quot;，而不是&quot;and&quot;？这里译者就先采用直译。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#diagnostic-attributes" id="diagnostic-attributes">Diagnostic attributes</a></h1>
<h1><a class="header" href="#诊断属性" id="诊断属性">诊断属性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/diagnostics.md">diagnostics.md</a><br />
commit: 12a4832c8eec1ad0df3edfb681571821708e0410 <br />
本章译文最后维护日期：2021-4-6</p>
</blockquote>
<p>以下<a href="attributes/../attributes.html">属性</a>用于在编译期间控制或生成诊断消息。</p>
<h2><a class="header" href="#lint-check-attributes" id="lint-check-attributes">Lint check attributes</a></h2>
<h2><a class="header" href="#lint检查类属性" id="lint检查类属性">lint检查类属性</a></h2>
<p>（译者注：lint在原文里有时当名词用，有时当动词用，本文统一翻译成名词，意思就是一种被命名的 lint检查模式）</p>
<p>lint检查(lint check)系统命名了一些潜在的不良编码模式，（这些被命名的 lint检查就是一个一个的lint，）例如编写了不可能执行到的代码，就被命名为 unreachable-code lint，编写未提供文档的代码就被命名为 missing_docs lint。<code>allow</code>、<code>warn</code>、<code>deny</code> 和 <code>forbid</code> 这些能调整代码检查级别的属性被称为 lint级别属性，它们使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaListPaths</em></a>元项属性句法来指定接受此级别的各种 lint。代码实体应用了这些带了具体 lint 列表的 lint级别属性，编译器或相关代码检查工具就可以结合这两层属性对这段代码执行相应的代码检查和检查报告。</p>
<p>对任何名为 <code>C</code> 的 lint 来说：</p>
<ul>
<li><code>allow(C)</code> 会压制对 <code>C</code> 的检查，那这样的违规行为就不会被报告，</li>
<li><code>warn(C)</code> 警告违反 <code>C</code> 的，但继续编译。</li>
<li><code>deny(C)</code> 遇到违反 <code>C</code> 的情况会触发编译器报错(signals an error)，</li>
<li><code>forbid(C)</code> 与 <code>deny(C)</code> 相同，但同时会禁止以后再更改 lint级别，</li>
<li></li>
</ul>
<blockquote>
<p>注意：可以通过 <code>rustc -W help</code> 找到所有 <code>rustc</code> 支持的 lint，以及它们的默认设置，也可以在 <a href="https://doc.rust-lang.org/rustc/lints/index.html">rustc book</a> 中找到相关文档。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub mod m1 {
    // 这里忽略未提供文档的编码行为
    #[allow(missing_docs)]
    pub fn undocumented_one() -&gt; i32 { 1 }

    // 未提供文档的编码行为在这里将触发编译器告警
    #[warn(missing_docs)]
    pub fn undocumented_too() -&gt; i32 { 2 }

    // 未提供文档的编码行为在这里将触发编译器报错
    #[deny(missing_docs)]
    pub fn undocumented_end() -&gt; i32 { 3 }
}
<span class="boring">}
</span></code></pre></pre>
<p>Lint属性可以覆盖上一个属性指定的级别，但该级别不能更改禁止性的 Lint。这里的上一个属性是指语法树中更高级别的属性，或者是同一实体上的前一个属性，按从左到右的源代码顺序列出。</p>
<p>此示例展示了如何使用 <code>allow</code> 和 <code>warn</code> 来打开和关闭一个特定的 lint检查：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[warn(missing_docs)]
pub mod m2{
    #[allow(missing_docs)]
    pub mod nested {
        // 这里忽略未提供文档的编码行为
        pub fn undocumented_one() -&gt; i32 { 1 }

        // 尽管上面允许，但未提供文档的编码行为在这里将触发编译器告警
        #[warn(missing_docs)]
        pub fn undocumented_two() -&gt; i32 { 2 }
    }

    // 未提供文档的编码行为在这里将触发编译器告警
    pub fn undocumented_too() -&gt; i32 { 3 }
}
<span class="boring">}
</span></code></pre></pre>
<p>此示例展示了如何使用 <code>forbid</code> 来禁止对该 lint 使用 <code>allow</code>：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[forbid(missing_docs)]
pub mod m3 {
    // 试图切换到 allow级别将触发编译器报错
    #[allow(missing_docs)]
    /// 返回 2。
    pub fn undocumented_too() -&gt; i32 { 2 }
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：<code>rustc</code>允许在<a href="https://doc.rust-lang.org/rustc/lints/levels.html#via-compiler-flag">命令行</a>上设置 lint级别，也支持在<a href="https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints">setting caps</a>中设置 lint报告中的caps。</p>
</blockquote>
<h3><a class="header" href="#lint-groups" id="lint-groups">Lint groups</a></h3>
<h3><a class="header" href="#lint分组" id="lint分组">lint分组</a></h3>
<p>lint可以被组织成不同命名的组，以便相关lint的等级可以一起调整。使用命名组相当于给出该组中的 lint。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 这允许 &quot;unused&quot;组下的所有lint。
#[allow(unused)]
// 这个禁止动作将覆盖前面 &quot;unused&quot;组中的 &quot;unused_must_use&quot; lint。
#[deny(unused_must_use)]
fn example() {
    // 这里不会生成告警，因为 &quot;unused_variables&quot; lint 在 &quot;unused&quot;组下
    let x = 1;
    // 这里会产生报错信息，因为 &quot;unused_must_use&quot; lint 被标记为&quot;deny&quot;，而这行的返回结果未被使用
    std::fs::remove_file(&quot;some_file&quot;); // ERROR: unused `Result` that must be used
}
<span class="boring">}
</span></code></pre></pre>
<p>有一个名为 “warnings” 的特殊组，它包含 “warn”级别的所有 lint。“warnings”组会忽略属性的顺序，并对实体执行所有告警lint 检查。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">unsafe fn an_unsafe_fn() {}
</span>// 这里的两个属性的前后顺序无所谓
#[deny(warnings)]
// unsafe_code lint 默认是 &quot;allow&quot; 的。
#[warn(unsafe_code)]
fn example_err() {
    // 这里会编译报错，因为 `unsafe_code`告警的 lint 被提升为 &quot;deny&quot;级别了。
    unsafe { an_unsafe_fn() } // ERROR: usage of `unsafe` block
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#tool-lint-attributes" id="tool-lint-attributes">Tool lint attributes</a></h3>
<h3><a class="header" href="#工具类lint属性" id="工具类lint属性">工具类lint属性</a></h3>
<p>可以为 <code>allow</code>、<code>warn</code>、<code>deny</code> 或 <code>forbid</code> 这些调整代码检查级别的 lint属性添加/输入基于特定工具的 lint。注意该工具在当前作用域内可用才会起效。</p>
<p>工具类lint 只有在相关工具处于活动状态时才会做相应的代码模式检查。如果一个 lint级别属性，如 <code>allow</code>，引用了一个不存在的工具类lint，编译器将不会去警告不存在该 lint类，只有使用了该工具（，才会报告该 lint类不存在）。</p>
<p>在其他方面，这些工具类lint 就跟像常规的 lint 一样：</p>
<pre><pre class="playground"><code class="language-rust edition2018">// 将 clippy 的整个 `pedantic` lint组设置为告警级别
#![warn(clippy::pedantic)]
// 使来自 clippy的 `filter_map` lint 的警告静音
#![allow(clippy::filter_map)]

fn main() {
    // ...
}

// 使 clippy的 `cmp_nan` lint 静音，仅用于此函数
#[allow(clippy::cmp_nan)]
fn foo() {
    // ...
}
</code></pre></pre>
<blockquote>
<p>注意：<code>rustc</code> 当前识别的工具类lint 有 &quot;<a href="https://github.com/rust-lang/rust-clippy">clippy</a>&quot; 和 &quot;<a href="https://doc.rust-lang.org/rustdoc/lints.html">rustdoc</a>&quot;。</p>
</blockquote>
<h2><a class="header" href="#the-deprecated-attribute" id="the-deprecated-attribute">The <code>deprecated</code> attribute</a></h2>
<h2><a class="header" href="#deprecated属性" id="deprecated属性"><code>deprecated</code>属性</a></h2>
<p><em><code>deprecated</code>属性</em>将程序项标记为已弃用。<code>rustc</code> 将对被 <code>#[deprecated]</code> 限定的程序项的行为发出警告。<code>rustdoc</code> 将特别展示已弃用的程序项，包括展示 <code>since</code> 版本和 <code>note</code> 提示（如果可用）。</p>
<p><code>deprecated</code>属性有几种形式：</p>
<ul>
<li><code>deprecated</code> — 发布一个通用的弃用消息。</li>
<li><code>deprecated = &quot;message&quot;</code> — 在弃用消息中包含给定的字符串。</li>
<li><a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaListNameValueStr</em></a>元项属性句法形式里带有两个可选字段：
<ul>
<li><code>since</code> — 指定程序项被弃用时的版本号。<code>rustc</code> 目前不解释此字符串，但是像 <a href="https://github.com/rust-lang/rust-clippy">Clippy</a> 这样的外部工具可以检查此值的有效性。</li>
<li><code>note</code> — 指定一个应该包含在弃用消息中的字符串。这通常用于提供关于不推荐的解释和推荐首选替代。</li>
</ul>
</li>
</ul>
<p><code>deprecated</code>属性可以应用于任何<a href="attributes/../items.html">程序项</a>，<a href="attributes/../items/traits.html">trait项</a>，<a href="attributes/../items/enumerations.html">枚举变体</a>，<a href="attributes/../items/structs.html">结构体字段</a>，<a href="attributes/../items/external-blocks.html">外部块项</a>，或<a href="attributes/../macros-by-example.html">宏定义</a>。它不能应用于 <a href="attributes/../items/implementations.html#trait-implementations">trait实现项</a>。当应用于包含其他程序项的程序项时，如<a href="attributes/../items/modules.html">模块</a>或<a href="attributes/../items/implementations.html">实现</a>，所有子程序项都继承此 deprecation属性。</p>
<!-- 注意: 它只被 trait实现(AnnotationKind::Prohibited)拒绝。在这些之外的所有其他位置，它会被静默忽略。应用于元组结构体的字段时，此属性直接也被忽略。-->
<p>这有个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[deprecated(since = &quot;5.2&quot;, note = &quot;foo was rarely used. Users should instead use bar&quot;)]
pub fn foo() {}

pub fn bar() {}
<span class="boring">}
</span></code></pre></pre>
<p><a href="https://github.com/rust-lang/rfcs/blob/master/text/1270-deprecation.md">RFC</a> 内有动机说明和更多细节。</p>
<h2><a class="header" href="#the-must_use-attribute" id="the-must_use-attribute">The <code>must_use</code> attribute</a></h2>
<h2><a class="header" href="#must_use属性" id="must_use属性"><code>must_use</code>属性</a></h2>
<p><em><code>must_use</code>属性</em> 用于在值未被“使用”时发出诊断告警。它可以应用于用户定义的复合类型（<a href="attributes/../items/structs.html">结构体(<code>struct</code>)</a>、<a href="attributes/../items/enumerations.html">枚举(<code>enum</code>)</a> 和 <a href="attributes/../items/unions.html">联合体(<code>union</code>)</a>）、<a href="attributes/../items/functions.html">函数</a>和 <a href="attributes/../items/traits.html">trait</a>。</p>
<p><code>must_use</code>属性可以使用<a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法添加一些附加消息，如 <code>#[must_use = &quot;example message&quot;]</code>。该字符串将出现在告警消息里。</p>
<p>当用户定义的复合类型上使用了此属性，如果有该类型的<a href="attributes/../expressions.html">表达式</a>正好是<a href="attributes/../statements.html#expression-statements">表达式语句</a>的表达式，那就违反了 <code>unused_must_use</code> 这个 lint。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[must_use]
struct MustUse {
    // 一些字段
}

<span class="boring">impl MustUse {
</span><span class="boring">  fn new() -&gt; MustUse { MustUse {} }
</span><span class="boring">}
</span><span class="boring">
</span>// 违反 `unused_must_use` lint。
MustUse::new();
<span class="boring">}
</span></code></pre></pre>
<p>当函数上使用了此属性，如果此函数被当作<a href="attributes/../statements.html#expression-statements">表达式语句</a>的<a href="attributes/../expressions.html">表达式</a>的<a href="attributes/../expressions/call-expr.html">调用表达式</a>，那就违反了 <code>unused_must_use</code> lint。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[must_use]
fn five() -&gt; i32 { 5i32 }

// 违反 unused_must_use lint。
five();
<span class="boring">}
</span></code></pre></pre>
<p>当 [trait声明]中使用了此属性，如果<a href="attributes/../statements.html#expression-statements">表达式语句</a>的<a href="attributes/../expressions/call-expr.html">调用表达式</a>返回了此 trait 的 <a href="attributes/../types/impl-trait.html">trait实现(impl trait)</a> ，则违反了 <code>unused_must_use</code> lint。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[must_use]
trait Critical {}
impl Critical for i32 {}

fn get_critical() -&gt; impl Critical {
    4i32
}

// 违反 `unused_must_use` lint。
get_critical();
<span class="boring">}
</span></code></pre></pre>
<p>当 trait声明中的一函数上使用了此属性时，如果调用表达式是此 trait 的某个实现中的该函数时，该行为同样违反 <code>unused_must_use</code> lint。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {
    #[must_use]
    fn use_me(&amp;self) -&gt; i32;
}

impl Trait for i32 {
    fn use_me(&amp;self) -&gt; i32 { 0i32 }
}

// 违反 `unused_must_use` lint。
5i32.use_me();
<span class="boring">}
</span></code></pre></pre>
<p>当在 trait实现里的函数上使用 <code>must_use</code>属性时，此属性将被忽略。</p>
<blockquote>
<p>注意：包含了此（属性应用的程序项产生的值）的普通空操作(no-op)表达式不会违反该 lint。例如，将此类值包装在没有实现 <a href="attributes/../special-types-and-traits.html#drop"><code>Drop</code></a> 的类型中，然后不使用该类型，并成为未使用的<a href="attributes/../expressions/block-expr.html">块表达式</a>的最终表达式(final expression)。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[must_use]
fn five() -&gt; i32 { 5i32 }

// 这些都不违反 unused_must_use lint。
(five(),);
Some(five());
{ five() };
if true { five() } else { 0i32 };
match true {
    _ =&gt; five()
};
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<blockquote>
<p>注意：当一个必须使用的值被故意丢弃时，使用带有模式 <code>_</code> 的<a href="attributes/../statements.html#let-statements">let语句</a>是惯用的方法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[must_use]
fn five() -&gt; i32 { 5i32 }

// 不违反 unused_must_use lint。
let _ = five();
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<h1><a class="header" href="#code-generation-attributes" id="code-generation-attributes">Code generation attributes</a></h1>
<h1><a class="header" href="#代码生成属性" id="代码生成属性">代码生成属性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/codegen.md">codegen.md</a><br />
commit: 7cdf88d28428065209e49ee70e28af86fcc64351 <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<p>下述<a href="attributes/../attributes.html">属性</a>用于控制代码生成。</p>
<h2><a class="header" href="#optimization-hints" id="optimization-hints">Optimization hints</a></h2>
<h2><a class="header" href="#优化提示" id="优化提示">优化提示</a></h2>
<p><code>cold</code><a href="attributes/../attributes.html">属性</a>和 <code>inline</code>属性给出了某种代码生成方式的提示建议，这种方式可能比没有此提示时更快。这些属性只是提示，可能会被忽略。</p>
<p>这两个属性都可以在<a href="attributes/../items/functions.html">函数</a>上使用。当这类属性应用于 <a href="attributes/../items/traits.html">trait</a> 中的函数上时，它们只在那些没有被 trait实现所覆盖的默认函数上生效，而不是所有 trait实现中用到的函数上都生效。这两属性对 trait 中那些没有函数体的函数没有影响。</p>
<h3><a class="header" href="#the-inline-attribute" id="the-inline-attribute">The <code>inline</code> attribute</a></h3>
<h3><a class="header" href="#内联inline属性" id="内联inline属性">内联(<code>inline</code>)属性</a></h3>
<p><em><code>inline</code><a href="attributes/../attributes.html">属性</a></em> 的意义是暗示在调用者(caller)中放置此（属性限定的）函数的副本，而不是在定义此（属性限定的）函数的地方生此函数的代码，然后去让别处代码来调用此函数。</p>
<blockquote>
<p><em><strong>注意</strong></em>：<code>rustc</code> 编译器会根据启发式算法(internal heuristics)<sup class="footnote-reference"><a href="#译者注1">1</a></sup>自动内联函数。不正确的内联函数会使程序变慢，所以应该小心使用此属性。</p>
</blockquote>
<p>使用内联(<code>inline</code>)属性有三种方法：</p>
<ul>
<li><code>#[inline]</code> <em>暗示</em>执行内联扩展。</li>
<li><code>#[inline(always)]</code> <em>暗示</em>应该一直执行内联扩展。</li>
<li><code>#[inline(never)]</code> <em>暗示</em>应该从不执行内联扩展。</li>
</ul>
<blockquote>
<p><em><strong>注意</strong></em>: <code>#[inline]</code> 在每种形式中都是一个提示，不是<em>必须</em>要在调用者放置此属性限定的函数的副本。</p>
</blockquote>
<h3><a class="header" href="#the-cold-attribute" id="the-cold-attribute">The <code>cold</code> attribute</a></h3>
<h3><a class="header" href="#cold属性" id="cold属性"><code>cold</code>属性</a></h3>
<p><em><code>cold</code><a href="attributes/../attributes.html">属性</a></em> 暗示此（属性限定的）函数不太可能被调用。</p>
<h2><a class="header" href="#the-no_builtins-attribute" id="the-no_builtins-attribute">The <code>no_builtins</code> attribute</a></h2>
<h2><a class="header" href="#no_builtins属性" id="no_builtins属性"><code>no_builtins</code>属性</a></h2>
<p><em><code>no_builtins</code><a href="attributes/../attributes.html">属性</a></em> 可以应用在 crate 级别，用以禁用对假定存在的库函数调用的某些代码模式优化。<sup class="footnote-reference"><a href="#译者注2">2</a></sup></p>
<h2><a class="header" href="#the-target_feature-attribute" id="the-target_feature-attribute">The <code>target_feature</code> attribute</a></h2>
<h2><a class="header" href="#target_feature属性" id="target_feature属性"><code>target_feature</code>属性</a></h2>
<p><em><code>target_feature</code>[属性]</em> 可应用于函数上，用来为特定的平台架构特性(platform architecture features)启用该函数的代码生成功能。它使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaListNameValueStr</em></a>元项属性句法来启用（该平台支持的）特性，但这次要求这个句法里只能有一个 <code>enable</code>键，其对应值是一个逗号分隔的由平台特性名字组成的符串。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">#[cfg(target_feature = &quot;avx2&quot;)]
</span>#[target_feature(enable = &quot;avx2&quot;)]
unsafe fn foo_avx2() {}
<span class="boring">}
</span></code></pre></pre>
<p>每个<a href="attributes/../conditional-compilation.html#target_arch">目标架构</a>都有一组可以被启用的特性。为不是当前 crate 的编译目标下的CPU架构指定需启用的特性是错误的。</p>
<p>调用一个编译时启用了某特性的函数，但当前程序运行的平台并不支持该特性，那这将导致出现<a href="attributes/../behavior-considered-undefined.html">未定义行为</a>。</p>
<p>应用了 <code>target_feature</code> 的函数不会内联到不支持给定特性的上下文中。<code>#[inline(always)]</code> 属性不能与 <code>target_feature</code>属性一起使用。</p>
<h3><a class="header" href="#available-features" id="available-features">Available features</a></h3>
<h3><a class="header" href="#可用特性" id="可用特性">可用特性</a></h3>
<p>下面是可用的特性的名称列表。</p>
<h4><a class="header" href="#x86-or-x86_64" id="x86-or-x86_64"><code>x86</code> or <code>x86_64</code></a></h4>
<p>在这两种平台架构下,<code>#[target_feature]</code> 只能应用于<a href="attributes/../unsafe-functions.html">非安全(<code>unsafe</code>)函数</a>。</p>
<table><thead><tr><th>特性</th><th>隐式启用</th><th>描述</th><th>中文描述</th></tr></thead><tbody>
<tr><td><code>aes</code></td><td><code>sse2</code></td><td><a href="https://en.wikipedia.org/wiki/AES_instruction_set">AES</a> — Advanced Encryption Standard</td><td>高级加密标准</td></tr>
<tr><td><code>avx</code></td><td><code>sse4.2</code></td><td><a href="https://en.wikipedia.org/wiki/Advanced_Vector_Extensions">AVX</a> — Advanced Vector Extensions</td><td>高级矢量扩展指令集</td></tr>
<tr><td><code>avx2</code></td><td><code>avx</code></td><td><a href="https://en.wikipedia.org/wiki/Advanced_Vector_Extensions#AVX2">AVX2</a> — Advanced Vector Extensions 2</td><td>高级矢量扩展指令集2</td></tr>
<tr><td><code>bmi1</code></td><td></td><td><a href="https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets">BMI1</a> — Bit Manipulation Instruction Sets</td><td>位操作指令集</td></tr>
<tr><td><code>bmi2</code></td><td></td><td><a href="https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets#BMI2">BMI2</a> — Bit Manipulation Instruction Sets 2</td><td>位操作指令集2</td></tr>
<tr><td><code>fma</code></td><td><code>avx</code></td><td><a href="https://en.wikipedia.org/wiki/FMA_instruction_set">FMA3</a> — Three-operand fused multiply-add</td><td>三操作乘加指令</td></tr>
<tr><td><code>fxsr</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/fxsave"><code>fxsave</code></a> and <a href="https://www.felixcloutier.com/x86/fxrstor"><code>fxrstor</code></a> — Save and restore x87 FPU, MMX Technology, and SSE State</td><td>保存/恢复 x87 FPU、MMX技术，SSE状态</td></tr>
<tr><td><code>lzcnt</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/lzcnt"><code>lzcnt</code></a> — Leading zeros count</td><td>前导零计数</td></tr>
<tr><td><code>pclmulqdq</code></td><td><code>sse2</code></td><td><a href="https://www.felixcloutier.com/x86/pclmulqdq"><code>pclmulqdq</code></a> — Packed carry-less multiplication quadword</td><td>压缩的四字（16字节）无进位乘法，主用于加解密处理</td></tr>
<tr><td><code>popcnt</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/popcnt"><code>popcnt</code></a> — Count of bits set to 1</td><td>位1计数，即统计有多少个“为1的位”</td></tr>
<tr><td><code>rdrand</code></td><td></td><td><a href="https://en.wikipedia.org/wiki/RdRand"><code>rdrand</code></a> — Read random number</td><td>从芯片上的硬件随机数生成器中获取随机数</td></tr>
<tr><td><code>rdseed</code></td><td></td><td><a href="https://en.wikipedia.org/wiki/RdRand"><code>rdseed</code></a> — Read random seed</td><td>从芯片上的硬件随机数生成器中获取为伪随机数生成器设定的种子</td></tr>
<tr><td><code>sha</code></td><td><code>sse2</code></td><td><a href="https://en.wikipedia.org/wiki/Intel_SHA_extensions">SHA</a> — Secure Hash Algorithm</td><td>安全哈希算法</td></tr>
<tr><td><code>sse</code></td><td></td><td><a href="https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions">SSE</a> — Streaming <abbr title="Single Instruction Multiple Data">SIMD</abbr> Extensions</td><td>单指令多数据流扩展指令集</td></tr>
<tr><td><code>sse2</code></td><td><code>sse</code></td><td><a href="https://en.wikipedia.org/wiki/SSE2">SSE2</a> — Streaming SIMD Extensions 2</td><td>单指令多数据流扩展指令集2</td></tr>
<tr><td><code>sse3</code></td><td><code>sse2</code></td><td><a href="https://en.wikipedia.org/wiki/SSE3">SSE3</a> — Streaming SIMD Extensions 3</td><td>单指令多数据流扩展指令集3</td></tr>
<tr><td><code>sse4.1</code></td><td><code>ssse3</code></td><td><a href="https://en.wikipedia.org/wiki/SSE4#SSE4.1">SSE4.1</a> — Streaming SIMD Extensions 4.1</td><td>单指令多数据流扩展指令集4.1</td></tr>
<tr><td><code>sse4.2</code></td><td><code>sse4.1</code></td><td><a href="https://en.wikipedia.org/wiki/SSE4#SSE4.2">SSE4.2</a> — Streaming SIMD Extensions 4.2</td><td>单指令多数据流扩展指令集4.2</td></tr>
<tr><td><code>ssse3</code></td><td><code>sse3</code></td><td><a href="https://en.wikipedia.org/wiki/SSSE3">SSSE3</a> — Supplemental Streaming SIMD Extensions 3</td><td>增补单指令多数据流扩展指令集3</td></tr>
<tr><td><code>xsave</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/xsave"><code>xsave</code></a> — Save processor extended states</td><td>保存处理器扩展状态</td></tr>
<tr><td><code>xsavec</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/xsavec"><code>xsavec</code></a> — Save processor extended states with compaction</td><td>压缩保存处理器扩展状态</td></tr>
<tr><td><code>xsaveopt</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/xsaveopt"><code>xsaveopt</code></a> — Save processor extended states optimized</td><td>xsave 指令集的优化版</td></tr>
<tr><td><code>xsaves</code></td><td></td><td><a href="https://www.felixcloutier.com/x86/xsaves"><code>xsaves</code></a> — Save processor extended states supervisor</td><td>保存处理器扩展状态监视程序</td></tr>
</tbody></table>
<!-- 保持各个链接靠近其表格，便于以后的增删改 -->
<h4><a class="header" href="#wasm32-or-wasm64" id="wasm32-or-wasm64"><code>wasm32</code> or <code>wasm64</code></a></h4>
<p>在这两个平台下，安全函数和<a href="attributes/../unsafe-functions.html">非安全函数</a>均可使用<code>#[target_feature]</code>。</p>
<table><thead><tr><th>特性</th><th>描述</th></tr></thead><tbody>
<tr><td><code>simd128</code></td><td><a href="https://github.com/webassembly/simd">WebAssembly simd 提案</a></td></tr>
</tbody></table>
<h3><a class="header" href="#additional-information" id="additional-information">Additional information</a></h3>
<h3><a class="header" href="#附加信息" id="附加信息">附加信息</a></h3>
<p>请参阅 <a href="attributes/../conditional-compilation.html#target_feature"><code>target_feature</code>-条件编译选项</a>，了解如何基于编译时的设置来有选择地启用或禁用对某些代码的编译。注意，条件编译选项不受 <code>target_feature</code>属性的影响，只是被整个 crate 启用的特性所驱动。</p>
<p>有关 x86 平台上的运行时特性检测，请参阅标准库中的 <a href="https://doc.rust-lang.org/std/macro.is_x86_feature_detected.html"><code>is_x86_feature_detected</code></a>宏。</p>
<blockquote>
<p>注意：<code>rustc</code> 为每个编译目标和 CPU 启用了一组默认特性。编译时，可以使用命令行参数 <a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#target-cpu"><code>-C target-cpu</code></a> 选择目标 CPU。可以通过命令行参数 <a href="https://doc.rust-lang.org/rustc/codegen-options/index.html#target-feature"><code>-C target-feature</code></a> 来为整个 crate 启用或禁用某些单独的特性。</p>
</blockquote>
<h2><a class="header" href="#the-track_caller-attribute" id="the-track_caller-attribute">The <code>track_caller</code> attribute</a></h2>
<h2><a class="header" href="#track_caller属性" id="track_caller属性"><code>track_caller</code>属性</a></h2>
<p><code>track_caller</code>属性可以应用于除程序入口函数 <code>fn main</code> 之外的任何带有 <a href="attributes/../items/external-blocks.html#abi"><code>&quot;Rust&quot;</code> ABI</a> 的函数。当此属性应用于 trait声明中的函数或方法时，该属性将应用在其所有的实现上。如果 trait 本身提供了带有该属性的默认函数实现，那么该属性也应用于其覆盖实现(override implementations)。</p>
<p>当应用于外部(<code>extern</code>)块中的函数上时，该属性也必须应用于此函数的任何链接实现(linked implementations)上，否则将导致未定义行为。当此属性应用在一个外部(<code>extern</code>)块内可用的函数上时，该外部(<code>extern</code>)块中的对该函数的声明也必须带上此属性，否则将导致未定义行为。</p>
<h3><a class="header" href="#behavior" id="behavior">Behavior</a></h3>
<h3><a class="header" href="#表现" id="表现">表现</a></h3>
<p>将此属性应用到函数 <code>f</code> 上将允许 <code>f</code> 内的代码获得 <code>f</code> 被调用时建立的调用栈的“最顶层”的调用的<a href="https://doc.rust-lang.org/core/panic/struct.Location.html">位置(<code>Location</code>)</a>信息的提示。从观察的角度来看，此属性的实现表现地就像从 <code>f</code> 所在的帧向上遍历调用栈，定位找到最近的有<em>非此属性限定</em>的调用函数 <code>outer</code>，并返回 <code>outer</code> 调用时的<a href="https://doc.rust-lang.org/core/panic/struct.Location.html">位置(<code>Location</code>)</a>信息。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[track_caller]
fn f() {
    println!(&quot;{}&quot;, std::panic::Location::caller());
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：<code>core</code> 提供了 <a href="https://doc.rust-lang.org/core/panic/struct.Location.html#method.caller"><code>core::panic::Location::caller</code></a> 来观察调用者的位置。它封装(wrap)了由 <code>rustc</code> 实现的内部函数(intrinsic) <a href="https://doc.rust-lang.org/core/intrinsics/fn.caller_location.html"><code>core::intrinsics::caller_location</code></a>。</p>
</blockquote>
<blockquote>
<p>注意：由于结果 <code>Location</code> 是一个提示，所以具体实现可能会提前终止对堆栈的遍历。请参阅<a href="attributes/codegen.html#limitations">限制</a>以了解重要的注意事项。</p>
</blockquote>
<h4><a class="header" href="#examples-1" id="examples-1">Examples</a></h4>
<h4><a class="header" href="#示例-2" id="示例-2">示例</a></h4>
<p>当 <code>f</code> 直接被 <code>calls_f</code> 调用时，<code>f</code> 中的代码观察其在 <code>calls_f</code> 内的调用位置：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">#[track_caller]
</span><span class="boring">fn f() {
</span><span class="boring">    println!(&quot;{}&quot;, std::panic::Location::caller());
</span><span class="boring">}
</span>fn calls_f() {
    f(); // &lt;-- f() 将打印此处的位置信息
}
<span class="boring">}
</span></code></pre></pre>
<p><code>f</code> 被另一个有此属性限定的函数 <code>g</code> 调用，<code>g</code> 又被 <code>calls_g</code>' 调用，<code>f</code> 和 <code>g</code> 内的代码又同时观察 <code>g</code> 在 <code>calls_g</code> 内的调用位置：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">#[track_caller]
</span><span class="boring">fn f() {
</span><span class="boring">    println!(&quot;{}&quot;, std::panic::Location::caller());
</span><span class="boring">}
</span>#[track_caller]
fn g() {
    println!(&quot;{}&quot;, std::panic::Location::caller());
    f();
}

fn calls_g() {
    g(); // &lt;-- g() 将两次打印此处的位置信息，一次是它自己，一次是此 f() 里来的
}
<span class="boring">}
</span></code></pre></pre>
<p>当<code>g</code> 又被另一个有此属性限定的函数 <code>h</code> 调用，而<code>g</code> 又被 <code>calls_h</code>' 调用，<code>f</code>、<code>g</code> 和 <code>h</code> 内的代码又同时观察 <code>h</code> 在 <code>calls_h</code> 内的调用位置：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">#[track_caller]
</span><span class="boring">fn f() {
</span><span class="boring">    println!(&quot;{}&quot;, std::panic::Location::caller());
</span><span class="boring">}
</span><span class="boring">#[track_caller]
</span><span class="boring">fn g() {
</span><span class="boring">    println!(&quot;{}&quot;, std::panic::Location::caller());
</span><span class="boring">    f();
</span><span class="boring">}
</span>#[track_caller]
fn h() {
    println!(&quot;{}&quot;, std::panic::Location::caller());
    g();
}

fn calls_h() {
    h(); // &lt;-- 将三次打印此处的位置信息，一次是它自己，一次是此 g() 里来，一次是从 f() 里来的
}
<span class="boring">}
</span></code></pre></pre>
<p>以此类推。</p>
<h3><a class="header" href="#limitations" id="limitations">Limitations</a></h3>
<h3><a class="header" href="#限制" id="限制">限制</a></h3>
<p><code>track_caller</code>属性获取的信息是只是一个提示信息，实现不需要维护它。</p>
<p>特别是，将带有 <code>#[track_caller]</code> 的函数自动强转为函数指针会创建一个填充对象，该填充对象在观察者看来似乎是在此(属性限定的)函数的定义处调用的，从而在这层虚拟调用中丢失了实际的调用者信息。这种自动强转情况的一个常见示例是创建方法被此属性限定的 trait对象<sup class="footnote-reference"><a href="#译者注3">3</a></sup> 。</p>
<blockquote>
<p>注意：前面提到的函数指针填充对象是必需的，因为 <code>rustc</code> 会通过向函数的 ABI 附加一个隐式参数来实现代码生成(codegen)上下文中的 <code>track_caller</code>，但这种添加是不健壮的(unsound)，因为该隐式参数不是函数类型的一部分，那给定的函数指针类型可能引用也可能不引用具有此属性的函数。这里创建一个填充对象会对函数指针的调用方隐藏隐式参数，从而保持可靠性。</p>
</blockquote>
<div class="footnote-definition" id="译者注1"><sup class="footnote-definition-label">1</sup>
<p>可字面理解为内部反复试探。</p>
</div>
<div class="footnote-definition" id="译者注2"><sup class="footnote-definition-label">2</sup>
<p>默认情况下，Rust 编译器会默认某些标准库函数在编译时可用，编译器也会把当前编译的代码往这些库函数可用的方向去优化。</p>
</div>
<div class="footnote-definition" id="译者注3"><sup class="footnote-definition-label">3</sup>
<p>因为 trait对象的值不能直接使用，只能自动强转为指针引用，那这里的调用就无法观察到真实的调用位置。</p>
</div>
<h1><a class="header" href="#limits" id="limits">Limits</a></h1>
<h1><a class="header" href="#极值设置" id="极值设置">极值设置</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/limits.md">limits.md</a><br />
commit: 8758f30a7d62513cb3caea30000850c9742f2438 <br />
本章译文最后维护日期：2021-5-29</p>
</blockquote>
<p>以下<a href="attributes/../attributes.html">属性</a>影响部分编译期参数的极限值设置。</p>
<h2><a class="header" href="#the-recursion_limit-attribute" id="the-recursion_limit-attribute">The <code>recursion_limit</code> attribute</a></h2>
<h2><a class="header" href="#recursion_limit属性" id="recursion_limit属性"><code>recursion_limit</code>属性</a></h2>
<p><em><code>recursion_limit</code>属性</em>可以应用于 <a href="attributes/../crates-and-source-files.html">crate</a> 级别，为可能无限递归的编译期操作（如宏扩展或自动解引用）设置最大递归深度。它使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法来指定递归深度。</p>
<blockquote>
<p>注意：<code>rustc</code> 中这个参数的默认值是128。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span>#![recursion_limit = &quot;4&quot;]

<span class="boring">fn main() {
</span>macro_rules! a {
    () =&gt; { a!(1) };
    (1) =&gt; { a!(2) };
    (2) =&gt; { a!(3) };
    (3) =&gt; { a!(4) };
    (4) =&gt; { };
}

// 这无法扩展，因为它需要大于4的递归深度。
a!{}
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span>#![recursion_limit = &quot;1&quot;]

<span class="boring">fn main() {
</span>// 这里的失败是因为需要两个递归步骤来自动解引用
(|_: &amp;u8| {})(&amp;&amp;&amp;1);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#the-type_length_limit-attribute" id="the-type_length_limit-attribute">The <code>type_length_limit</code> attribute</a></h2>
<h2><a class="header" href="#type_length_limit属性" id="type_length_limit属性"><code>type_length_limit</code>属性</a></h2>
<p><em><code>type_length_limit</code>属性</em>限制在单态化过程中构造具体类型时所做的最大类型替换次数。它应用于 <a href="attributes/../crates-and-source-files.html">crate</a> 级别，并使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法来设置类型替换数量的上限。</p>
<blockquote>
<p>注意：<code>rustc</code> 中这个参数的默认值是 1048576。</p>
</blockquote>
<pre><code class="language-rust compile_fail ignore">#![type_length_limit = &quot;4&quot;]

fn f&lt;T&gt;(x: T) {}

// 这里的编译失败是因为单态化 `f::&lt;((((i32,), i32), i32), i32)&gt;` 需要大于4个类型元素。
f(((((1,), 2), 3), 4));
</code></pre>
<h1><a class="header" href="#type-system-attributes" id="type-system-attributes">Type system attributes</a></h1>
<h1><a class="header" href="#类型系统属性" id="类型系统属性">类型系统属性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/attributes/type_system.md">type_system.md</a><br />
commit: d8cbe4eedb77bae3db9eff87b1238e7e23f6ae92 <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<p>以下<a href="attributes/../attributes.html">属性</a>用于改变类型的使用方式。</p>
<h2><a class="header" href="#the-non_exhaustive-attribute" id="the-non_exhaustive-attribute">The <code>non_exhaustive</code> attribute</a></h2>
<h2><a class="header" href="#non_exhaustive属性" id="non_exhaustive属性"><code>non_exhaustive</code>属性</a></h2>
<p><em><code>non_exhaustive</code>属性</em>表示类型或变体将来可能会添加更多字段或变体。它可以应用在<a href="attributes/../items/structs.html">结构体(<code>struct</code>)</a>上、<a href="attributes/../items/enumerations.html">枚举(<code>enum</code>)</a>上 和 枚举变体上。</p>
<p><code>non_exhaustive</code>属性使用 <a href="attributes/../attributes.html#meta-item-attribute-syntax"><em>MetaWord</em></a>元项属性句法，因此不接受任何输入。</p>
<p>在当前（<code>non_exhaustive</code>限制的类型的）定义所在的 crate 内，<code>non_exhaustive</code> 没有效果。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[non_exhaustive]
pub struct Config {
    pub window_width: u16,
    pub window_height: u16,
}

#[non_exhaustive]
pub enum Error {
    Message(String), // 译者注：此变体为元组变体
    Other,
}

pub enum Message {
    #[non_exhaustive] Send { from: u32, to: u32, contents: String },
    #[non_exhaustive] Reaction(u32),
    #[non_exhaustive] Quit,
}

// 非穷尽结构体可以在定义它的 crate 中正常构建。
let config = Config { window_width: 640, window_height: 480 };

// 非穷尽结构体可以在定义它的 crate 中进行详尽匹配
if let Config { window_width, window_height } = config {
    // ...
}

let error = Error::Other;
let message = Message::Reaction(3);

// 非穷尽枚举可以在定义它的 crate 中进行详尽匹配
match error {
    Error::Message(ref s) =&gt; { },
    Error::Other =&gt; { },
}

match message {
    // 非穷尽变体可以在定义它的 crate 中进行详尽匹配
    Message::Send { from, to, contents } =&gt; { },
    Message::Reaction(id) =&gt; { },
    Message::Quit =&gt; { },
}
<span class="boring">}
</span></code></pre></pre>
<p>在定义所在的 crate之外，标注为 <code>non_exhaustive</code> 的类型须在添加新字段或变体时保持向后兼容性。</p>
<p>非穷尽类型(non-exhaustive types)不能在定义它的 crate 之外构建：</p>
<ul>
<li>非穷尽变体（<a href="attributes/../items/structs.html">结构体(<code>struct</code>)</a>或<a href="attributes/../items/enumerations.html">枚举变体(<code>enum</code> variant)</a>）不能用 <a href="attributes/../expressions/struct-expr.html"><em>StructExpression</em></a>句法（包括<a href="attributes/../expressions/struct-expr.html#functional-update-syntax">函数式更新(functional update)句法</a>）构建。</li>
<li><a href="attributes/../items/enumerations.html">枚举(<code>enum</code>)</a>实例能被构建。</li>
</ul>
<p>示例：（译者注：本例把上例看成本例的 <code>upstream</code> ）</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">// `Config`、`Error` `Message`是在上游 crate 中定义的类型，这些类型已被标注为 `#[non_exhaustive]`。
use upstream::{Config, Error, Message};

// 不能构造 `Config` 的实例，如果在 `upstream` 的新版本中添加了新字段，则本地编译会失败，因此不允许这样做。
let config = Config { window_width: 640, window_height: 480 };

// 可以构造 `Error` 的实例，引入的新变体不会导致编译失败。
let error = Error::Message(&quot;foo&quot;.to_string());

// 无法构造 `Message::Send` 或 `Message::Reaction` 的实例，
// 如果在 `upstream` 的新版本中添加了新字段，则本地编译失败，因此不允许。
let message = Message::Send { from: 0, to: 1, contents: &quot;foo&quot;.to_string(), };
let message = Message::Reaction(0);

// 无法构造 `Message::Quit` 的实例，
// 如果 `upstream` 内的 `Message::Quit` 的因为添加字段变成元组变体(tuple-variant/tuple variant)后，则本地编译失败。
let message = Message::Quit;
</code></pre>
<p>在定义所在的 crate 之外对非穷尽类型进行匹配，有如下限制：</p>
<ul>
<li>当模式匹配一个非穷尽变体（<a href="attributes/../items/structs.html">结构体(<code>struct</code>)</a>或<a href="attributes/../items/enumerations.html">枚举变体(<code>enum</code> variant)</a>）时，必须使用 <a href="attributes/../patterns.html#struct-patterns"><em>StructPattern</em></a>句法进行匹配，其匹配臂必须有一个为 <code>..</code>。元组变体的构造函数的可见性降低为 <code>min($vis, pub(crate))</code>。</li>
<li>当模式匹配在一个非穷尽的<a href="attributes/../items/enumerations.html">枚举(<code>enum</code>)</a>上时，增加对单个变体的匹配无助于匹配臂需满足枚举变体的穷尽性(exhaustiveness)的这一要求。</li>
</ul>
<p>示例：（译者注：可以把上上例看成本例的 <code>upstream</code> ）</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">// `Config`、`Error` `Message` 是在上游 crate 中定义的类型，这些类型已被标注为 `#[non_exhaustive]`。
use upstream::{Config, Error, Message};

// 不包含通配符匹配臂，无法匹配非穷尽枚举。
match error {
  Error::Message(ref s) =&gt; { },
  Error::Other =&gt; { },
  // 加上 `_ =&gt; {},` 就能编译通过
}

// 不包含通配符匹配臂，无法匹配非穷尽结构体
if let Ok(Config { window_width, window_height }) = config {
    // 加上 `..` 就能编译通过
}

match message {
  // 没有通配符，无法匹配非穷尽（结构体/枚举内的）变体
  Message::Send { from, to, contents } =&gt; { },
  // 无法匹配非穷尽元组或单元枚举变体(unit enum variant)。
  Message::Reaction(type) =&gt; { },
  Message::Quit =&gt; { },
}
</code></pre>
<p>非穷尽类型最好放在下游 crate 里。</p>
<h1><a class="header" href="#statements-and-expressions" id="statements-and-expressions">Statements and expressions</a></h1>
<h1><a class="header" href="#语句和表达式" id="语句和表达式">语句和表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/statements-and-expressions.md">statements-and-expressions.md</a><br />
commit: 4a2bdf896cd2df370a91d14cb8ba04e326cd21db <br />
本章译文最后维护日期：2020-11-11</p>
</blockquote>
<p>Rust <em>基本上</em>是一种表达式语言。这意味着大多数形式的求值或生成表达效果的计算的都是由<em>表达式</em>的统一句法类别来指导的。每一种表达式通常都可以<em>内嵌</em>到另一种表达式中，表达式的求值规则包括指定表达式产生的值和指定其各个子表达式的求值顺序。</p>
<p>对比之下，Rust 中的语句则<em>主要</em>用于包含表达式求值，以及显式地安排表达式的求值顺序。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#statements" id="statements">Statements</a></h1>
<h1><a class="header" href="#语句" id="语句">语句</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/statements.md">statements.md</a><br />
commit: f5cd2519c0e61a2c640345c2e5cda329008ead3a <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Statement</em> :<br />
      <code>;</code><br />
   | <a href="items.html"><em>Item</em></a><br />
   | <a href="statements.html#let-statements"><em>LetStatement</em></a><br />
   | <a href="statements.html#expression-statements"><em>ExpressionStatement</em></a><br />
   | <a href="macros.html#macro-invocation"><em>MacroInvocationSemi</em></a></p>
</blockquote>
<p><em>语句</em>是<a href="expressions/block-expr.html">块(block)</a><sup class="footnote-reference"><a href="#译者注">1</a></sup>的一个组件，反过来，块又是其外层<a href="expressions.html">表达式</a>或<a href="items/functions.html">函数</a>的组件。</p>
<p>Rust 有两种语句：<a href="statements.html#declaration-statements">声明语句(declaration statements)</a>和<a href="statements.html#expression-statements">表达式语句(expression statements)</a>。</p>
<h2><a class="header" href="#declaration-statements" id="declaration-statements">Declaration statements</a></h2>
<h2><a class="header" href="#声明语句" id="声明语句">声明语句</a></h2>
<p><em>声明语句</em>是在它自己封闭的语句块的内部引入一个或多个<em>名称</em>的语句。声明的名称可以表示新变量或新的<a href="items.html">程序项</a>。</p>
<p>这两种声明语句就是程序项声明语句和 let声明语句。</p>
<h3><a class="header" href="#item-declarations" id="item-declarations">Item declarations</a></h3>
<h3><a class="header" href="#程序项声明语句" id="程序项声明语句">程序项声明语句</a></h3>
<p><em>程序项声明语句</em>的句法形式与<a href="items/modules.html">模块</a>中的<a href="items.html">程序项声明</a>的句法形式相同。在语句块中声明的程序项会将其作用域限制为包含该语句的块。这类程序项以及在其内声明子项(sub-items)都没有给定的<a href="paths.html#canonical-paths">规范路径</a>。例外的是，只要程序项和 trait（如果有的话）的可见性允许，在（程序项声明语句内定义的和此程序项或 trait 关联的）<a href="items/implementations.html">实现</a>中定义的关联项在外层作用域内仍然是可访问的。除了这些区别外，它与在模块中声明的程序项的意义也是相同的。</p>
<p>程序项声明语句不会隐式捕获包含它的函数的泛型参数、参数和局部变量。如下，<code>inner</code> 不能访问 <code>outer_var</code>。</p>
<p><code>outer_var</code>.</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn outer() {
  let outer_var = true;

  fn inner() { /* outer_var 的作用域不包括这里 */ }

  inner();
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#let-statements" id="let-statements"><code>let</code> statements</a></h3>
<h3><a class="header" href="#let语句" id="let语句"><code>let</code>语句</a></h3>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LetStatement</em> :<br />
   <a href="attributes.html"><em>OuterAttribute</em></a><sup>*</sup> <code>let</code> <a href="patterns.html"><em>PatternNoTopAlt</em></a>
( <code>:</code> <a href="types.html"><em>Type</em></a> )<sup>?</sup> (<code>=</code> <a href="expressions.html"><em>Expression</em></a> )<sup>?</sup> <code>;</code></p>
</blockquote>
<p><em><code>let</code>语句</em>通过一个不可反驳型<a href="patterns.html">模式</a>引入了一组新的<a href="variables.html">变量</a>，变量由该模式给定。模式后面有一个可选的类型标注(annotation)，再后面是一个可选的初始化表达式。当没有给出类型标注时，编译器将自行推断类型，如果没有足够的信息来执行有限次的类型推断，则将触发编译器报错。由变量声明引入的任何变量从声明点到封闭块作用域的结束都是可见的，除非它们被另一个变量声明遮蔽。</p>
<h2><a class="header" href="#expression-statements" id="expression-statements">Expression statements</a></h2>
<h2><a class="header" href="#表达式语句" id="表达式语句">表达式语句</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ExpressionStatement</em> :<br />
      <a href="expressions.html"><em>ExpressionWithoutBlock</em></a> <code>;</code><br />
   | <a href="expressions.html"><em>ExpressionWithBlock</em></a> <code>;</code><sup>?</sup></p>
</blockquote>
<p><em>表达式语句</em>是对<a href="expressions.html">表达式</a>求值并忽略其结果的语句。通常，表达式语句存在的目的是触发对其内部的表达式的求值时的效果。</p>
<p>仅由<a href="expressions/block-expr.html">块表达式</a>或控制流表达式组成的表达式，如果它们在允许使用语句的上下文中使用时，是可以省略其后面的分号的。这有可能会导致解析歧义，因为它可以被解析为独立语句，也可以被解析为另一个表达式的一部分；下例中的控制流表达式被解析为一个语句。注意 <a href="expressions.html"><em>ExpressionWithBlock</em></a> 形式的表达式用作语句时，其类型必须是单元类型(<code>()</code>)。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let mut v = vec![1, 2, 3];
</span>v.pop();          // 忽略从 pop 返回的元素
if v.is_empty() {
    v.push(5);
} else {
    v.remove(0);
}                 // 分号可以省略。
[1];              // 单独的表达式语句，而不是索引表达式。
<span class="boring">}
</span></code></pre></pre>
<p>当省略后面的分号时，结果必须是 <code>()</code> 类型。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// bad: 下面块的类型是i32，而不是 `()` 
// Error: 预期表达式语句的返回值是 `()` 
// if true {
//   1
// }

// good: 下面块的类型是i32，（加`;`后的语句的返回值就是 `()`了）
if true {
  1
} else {
  2
};
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes-on-statements" id="attributes-on-statements">Attributes on Statements</a></h2>
<h2><a class="header" href="#语句上的属性" id="语句上的属性">语句上的属性</a></h2>
<p>语句可以有<a href="attributes.html">外部属性</a>。在语句中有意义的属性是 <a href="conditional-compilation.html"><code>cfg</code></a> 和 <a href="attributes/diagnostics.html#lint-check-attributes">lint检查类属性</a>。</p>
<div class="footnote-definition" id="译者注"><sup class="footnote-definition-label">1</sup>
<p>本书原文还有 <code>block of code</code> 的写法，这种有些类似于我们口语中说的那种任意的代码段的“代码块”。原文中 <code>block of code</code> 的典型情况是非安全(<code>unsafe</code>)块。</p>
</div>
<h1><a class="header" href="#expressions" id="expressions">Expressions</a></h1>
<h1><a class="header" href="#表达式" id="表达式">表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions.md">expressions.md</a><br />
commit: 97ba67cbee415e263a054e9ce68baf0e75dca2b0 <br />
本章译文最后维护日期：2021-07-11</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Expression</em> :<br />
      <em>ExpressionWithoutBlock</em><br />
   | <em>ExpressionWithBlock</em></p>
<p><em>ExpressionWithoutBlock</em> :<br />
   <a href="attributes.html"><em>OuterAttribute</em></a><sup>*</sup><a href="expressions.html#expression-attributes">†</a><br />
   (<br />
         <a href="expressions/literal-expr.html"><em>LiteralExpression</em></a><br />
      | <a href="expressions/path-expr.html"><em>PathExpression</em></a><br />
      | <a href="expressions/operator-expr.html"><em>OperatorExpression</em></a><br />
      | <a href="expressions/grouped-expr.html"><em>GroupedExpression</em></a><br />
      | <a href="expressions/array-expr.html"><em>ArrayExpression</em></a><br />
      | <a href="expressions/await-expr.html"><em>AwaitExpression</em></a><br />
      | <a href="expressions/array-expr.html#array-and-slice-indexing-expressions"><em>IndexExpression</em></a><br />
      | <a href="expressions/tuple-expr.html"><em>TupleExpression</em></a><br />
      | <a href="expressions/tuple-expr.html#tuple-indexing-expressions"><em>TupleIndexingExpression</em></a><br />
      | <a href="expressions/struct-expr.html"><em>StructExpression</em></a><br />
      | <a href="expressions/call-expr.html"><em>CallExpression</em></a><br />
      | <a href="expressions/method-call-expr.html"><em>MethodCallExpression</em></a><br />
      | <a href="expressions/field-expr.html"><em>FieldExpression</em></a><br />
      | <a href="expressions/closure-expr.html"><em>ClosureExpression</em></a><br />
      | <a href="expressions/loop-expr.html#continue-expressions"><em>ContinueExpression</em></a><br />
      | <a href="expressions/loop-expr.html#break-expressions"><em>BreakExpression</em></a><br />
      | <a href="expressions/range-expr.html"><em>RangeExpression</em></a><br />
      | <a href="expressions/return-expr.html"><em>ReturnExpression</em></a><br />
      | <a href="macros.html#macro-invocation"><em>MacroInvocation</em></a><br />
   )</p>
<p><em>ExpressionWithBlock</em> :<br />
   <a href="attributes.html"><em>OuterAttribute</em></a><sup>*</sup><a href="expressions.html#expression-attributes">†</a><br />
   (<br />
         <a href="expressions/block-expr.html"><em>BlockExpression</em></a><br />
      | <a href="expressions/block-expr.html#async-blocks"><em>AsyncBlockExpression</em></a><br />
      | <a href="expressions/block-expr.html#unsafe-blocks"><em>UnsafeBlockExpression</em></a><br />
      | <a href="expressions/loop-expr.html"><em>LoopExpression</em></a><br />
      | <a href="expressions/if-expr.html#if-expressions"><em>IfExpression</em></a><br />
      | <a href="expressions/if-expr.html#if-let-expressions"><em>IfLetExpression</em></a><br />
      | <a href="expressions/match-expr.html"><em>MatchExpression</em></a><br />
   )</p>
</blockquote>
<p>一个表达式可能有两个角色：它总是能产生<sup class="footnote-reference"><a href="#译者注1">1</a></sup>一个<em>值</em>；它还有可能表达出<em>效果(effects)</em>（也被称为“副作用(side effects)”）。表达式 <em>求值/计算为(evaluates to)</em> 值，并在 <em>求值(evaluation)</em> 期间表达出效果。 <br />
许多表达式包含子表达式，此子表达式也被称为此表达式的<em>操作数</em>。每种表达式都表达了以下几点含义：</p>
<ul>
<li>在对表达式求值时是否对操作数求值</li>
<li>对操作数求值的顺序</li>
<li>如何组合操作数的值来获取表达式的值</li>
</ul>
<p>基于对这几种含义的实现要求，表达式通过其内在结构规定了其执行结构。<br />
块只是另一种表达式，所以块、语句和表达式可以递归地彼此嵌套到任意深度。</p>
<blockquote>
<p><strong>注意</strong>：我们给表达式的操作数做了（如上）命名，以便于我们去讨论它们，但这些名称并没有最终稳定下来，以后可能还会更改。</p>
</blockquote>
<h2><a class="header" href="#expression-precedence" id="expression-precedence">Expression precedence</a></h2>
<h2><a class="header" href="#表达式的优先级" id="表达式的优先级">表达式的优先级</a></h2>
<p>Rust 运算符和表达式的优先级顺序如下，从强到弱。具有相同优先级的二元运算符按其结合(associativity)顺序做了分组。</p>
<table><thead><tr><th>运算符/表达式</th><th>结合性</th></tr></thead><tbody>
<tr><td>Paths（路径）</td><td></td></tr>
<tr><td>Method calls（方法调用）</td><td></td></tr>
<tr><td>Field expressions （字段表达式）</td><td>从左向右</td></tr>
<tr><td>Function calls, array indexing（函数调用，数组索引）</td><td></td></tr>
<tr><td><code>?</code></td><td></td></tr>
<tr><td>Unary（一元运算符） <code>-</code> <code>*</code> <code>!</code> <code>&amp;</code> <code>&amp;mut</code></td><td></td></tr>
<tr><td><code>as</code></td><td>从左向右</td></tr>
<tr><td><code>*</code> <code>/</code> <code>%</code></td><td>从左向右</td></tr>
<tr><td><code>+</code> <code>-</code></td><td>从左向右</td></tr>
<tr><td><code>&lt;&lt;</code> <code>&gt;&gt;</code></td><td>从左向右</td></tr>
<tr><td><code>&amp;</code></td><td>从左向右</td></tr>
<tr><td><code>^</code></td><td>从左向右</td></tr>
<tr><td><code>|</code></td><td>从左向右</td></tr>
<tr><td><code>==</code> <code>!=</code> <code>&lt;</code> <code>&gt;</code> <code>&lt;=</code> <code>&gt;=</code></td><td>需要圆括号</td></tr>
<tr><td><code>&amp;&amp;</code></td><td>从左向右</td></tr>
<tr><td><code>||</code></td><td>从左向右</td></tr>
<tr><td><code>..</code> <code>..=</code></td><td>需要圆括号</td></tr>
<tr><td><code>=</code> <code>+=</code> <code>-=</code> <code>*=</code> <code>/=</code> <code>%=</code> <br> <code>&amp;=</code> <code>|=</code> <code>^=</code> <code>&lt;&lt;=</code> <code>&gt;&gt;=</code></td><td>从右向左</td></tr>
<tr><td><code>return</code> <code>break</code> closures（返回、中断、闭包）</td><td></td></tr>
</tbody></table>
<h2><a class="header" href="#evaluation-order-of-operands" id="evaluation-order-of-operands">Evaluation order of operands</a></h2>
<h2><a class="header" href="#操作数的求值顺序" id="操作数的求值顺序">操作数的求值顺序</a></h2>
<p>下面的表达式列表都以相同的方式计算它们的操作数，具体列表后面也有详述。其他表达式要么不接受操作数，要么按照各自约定（后续章节会有讲述）的条件进行求值。</p>
<ul>
<li>解引用表达式(Dereference expression)</li>
<li>错误传播表达式(Error propagation expression)</li>
<li>取反表达式(Negation expression)</li>
<li>算术和二进制逻辑运算(Arithmetic and logical binary operators)</li>
<li>比较运算(Comparison operators)</li>
<li>类型转换表达式(Type cast expression)</li>
<li>分组表达式(Grouped expression)</li>
<li>数组表达式(Array expression)</li>
<li>等待表达式(Await expression)</li>
<li>索引表达式(Index expression)</li>
<li>元组表达式(Tuple expression)</li>
<li>元组索引表达式(Tuple index expression)</li>
<li>结构体表达式(Struct expression)</li>
<li>调用表达式(Call expression)</li>
<li>方法调用表达式(Method call expression)</li>
<li>字段表达式(Field expression)</li>
<li>中断表达式(Break expression)</li>
<li>区间表达式(Range expression)</li>
<li>返回表达式(Return expression)</li>
</ul>
<p>在实现执行这些表达式的效果之前，会先对这些表达式的操作数进行求值。拥有多个操作数的表达式会按照源代码书写的顺序从左到右计算。</p>
<blockquote>
<p><strong>注意</strong>：子表达式是一个表达式的操作数时，此子表达式内部的求值顺序是由根据前面的章节规定的优先级来确定的。</p>
</blockquote>
<p>例如，下面两个 <code>next</code>方法的调用总是以相同的顺序调用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">// 使用 vec 代替 array 来避免引用，因为在编写本例时，拥有内部元素的所有权的数组迭代器还没有稳定下来。
</span>let mut one_two = vec![1, 2].into_iter();
assert_eq!(
    (1, 2),
    (one_two.next().unwrap(), one_two.next().unwrap())
);
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><strong>注意</strong>：由于表达式是递归执行的，那这些表达式也会从最内层到最外层逐层求值，忽略兄弟表达式，直到没有（未求值的）内部子表达式为止。</p>
</blockquote>
<h2><a class="header" href="#place-expressions-and-value-expressions" id="place-expressions-and-value-expressions">Place Expressions and Value Expressions</a></h2>
<h2><a class="header" href="#位置表达式和值表达式" id="位置表达式和值表达式">位置表达式和值表达式</a></h2>
<p>表达式分为两大类：位置表达式和值表达式。跟在每个表达式中一样，操作数可以出现在位置上下文，也可出现在值上下文中。表达式的求值既依赖于它自己的类别，也依赖于它所在的上下文。</p>
<p><em>位置表达式</em>是表示内存位置的表达式。语言中表现为指向<strong>局部变量、<a href="items/static-items.html">静态变量</a>、<a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>(<code>*expr</code>)、<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">数组索引</a>表达式(<code>expr[expr]</code>)、<a href="expressions/field-expr.html">字段</a>引用(<code>expr.f</code>)、圆括号括起来的位置表达式</strong>的<a href="expressions/path-expr.html">路径</a>。所有其他形式的表达式都是值表达式。</p>
<p><em>值表达式</em>是代表实际值的表达式。</p>
<p>下面的上下文是<em>位置表达式</em>上下文：</p>
<ul>
<li><a href="expressions/operator-expr.html#assignment-expressions">赋值</a>或<a href="expressions/operator-expr.html#compound-assignment-expressions">复合赋值</a>表达式的左操作数。</li>
<li>一元运算符<a href="expressions/operator-expr.html#borrow-operators">借用</a>或<a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>的操作数。</li>
<li>字段表达式的操作数。</li>
<li>数组索引表达式的被索引操作数。</li>
<li>任何<a href="expressions.html#implicit-borrows">隐式借用</a>的操作数。</li>
<li><a href="statements.html#let-statements">let语句</a>的初始化器(initializer)。</li>
<li><a href="expressions/if-expr.html#if-let-expressions"><code>if let</code></a>表达式、<a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a>表达式或<a href="expressions/match-expr.html">匹配(<code>match</code>)</a>表达式的<a href="glossary.html#scrutinee">检验对象(scrutinee)</a>。</li>
<li>结构体表达式里的<a href="expressions/struct-expr.html#functional-update-syntax">函数式更新(functional update)</a>的基(base)。</li>
</ul>
<blockquote>
<p>注意：历史上，位置表达式被称为 <em>左值/lvalues</em>，值表达式被称为 <em>右值/rvalues</em>。</p>
</blockquote>
<h3><a class="header" href="#moved-and-copied-types" id="moved-and-copied-types">Moved and copied types</a></h3>
<h3><a class="header" href="#移动语义类型和复制语义类型" id="移动语义类型和复制语义类型">移动语义类型和复制语义类型</a></h3>
<p>当位置表达式在值表达式上下文中被求值时，或在模式中被值绑定时，这表示此值会*保存进(held in)*当前表达式代表的内存地址。如果该值的类型实现了 <a href="special-types-and-traits.html#copy"><code>Copy</code></a>，那么该值将被从原来的位置复制一份过来。如果该值的类型没有实现 <a href="special-types-and-traits.html#copy"><code>Copy</code></a>，但实现了 <a href="special-types-and-traits.html#sized"><code>Sized</code></a>，那么就有可能把该值从原来的位置移动(move)过来。从位置表达式里移出值对位置表达式也有要求，只有如下的位置表达式才可能把值从其中移出(move out)：</p>
<ul>
<li><a href="variables.html">变量</a>当前未被借用。</li>
<li><a href="expressions.html#temporaries">临时值(Temporary values)</a>。</li>
<li>可以移出且没实现 <a href="special-types-and-traits.html#drop"><code>Drop</code></a> 的位置表达式的字段。</li>
<li>对可移出且类型为 <a href="../std/boxed/struct.Box.html"><code>Box&lt;T&gt;</code></a> 的表达式作<a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>的结果。</li>
</ul>
<p>当把值从一个位置表达式里移出到一个局部变量时，此（表达式代表的）地址将被去初始化(deinitialized)，并且该地址在重新初始化之前无法被再次读取。<br />
除以上列出的情况外，任何在值表达式上下文中使用位置表达式都是错误的。</p>
<h3><a class="header" href="#mutability" id="mutability">Mutability</a></h3>
<h3><a class="header" href="#可变性" id="可变性">可变性</a></h3>
<p>如果一个位置表达式将会被<a href="expressions/operator-expr.html#assignment-expressions">赋值</a>、可变<a href="expressions/operator-expr.html#borrow-operators">借出</a>、<a href="expressions.html#implicit-borrows">隐式可变借出</a>或被绑定到包含 <code>ref mut</code> 模式上，则该位置表达式必须是<em>可变的(mutable)</em>。我们称这类位置表达式为<em>可变位置表达式</em>。与之相对，其他位置表达式称为<em>不可变位置表达式</em>。</p>
<p>下面的表达式可以是可变位置表达式上下文：</p>
<ul>
<li>当前未被借出的可变<a href="variables.html">变量</a>。</li>
<li><a href="items/static-items.html#mutable-statics">可变静态(<code>static</code>)项</a>。</li>
<li><a href="expressions.html#temporaries">临时值</a>。</li>
<li><a href="expressions/field-expr.html">字段</a>：在可变位置表达式上下文中，可以对此子表达式求值。</li>
<li>对 <code>*mut T</code> 指针的<a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>。</li>
<li>对类型为 <code>&amp;mut T</code> 的变量或变量的字段的解引用。注意：这条是下一条规则的必要条件的例外情况。<sup class="footnote-reference"><a href="#译者注2">2</a></sup></li>
<li>对实现 <code>DerefMut</code> 的类型的解引用，那对这里解出的表达式求值就需要在一个可变位置表达式上下文中进行。</li>
<li>对实现 <code>IndexMut</code> 的类型做<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">索引</a>，那对此检索出的表达式求值就需要在一个可变位置表达式上下文进行。注意对索引(index)本身的求值不用。</li>
</ul>
<h3><a class="header" href="#temporaries" id="temporaries">Temporaries</a></h3>
<h3><a class="header" href="#临时位置临时变量" id="临时位置临时变量">临时位置/临时变量</a></h3>
<p>在大多数位置表达式上下文中使用值表达式时，会创建一个临时的未命名内存位置，并将该位置初始为该值，然后这个表达式的求值结果就为该内存位置。此过程也有例外，就是把此临时表达式<a href="destructors.html#constant-promotion">提升</a>为一个静态项(<code>static</code>)。（译者注：这种情况下表达式将直接在编译时就求值了，求值的结果会根据编译器要求重新选择地址存储）。临时位置/临时变量的<a href="destructors.html#drop-scopes">销毁作用域(drop scope)</a>通常在包含它的最内层语句的结尾处。</p>
<h3><a class="header" href="#implicit-borrows" id="implicit-borrows">Implicit Borrows</a></h3>
<h3><a class="header" href="#隐式借用" id="隐式借用">隐式借用</a></h3>
<p>某些特定的表达式可以通过隐式借用一个表达式来将其视为位置表达式。例如，可以直接比较两个非固定尺寸的<a href="types/slice.html">切片</a>是否相等，因为 <code>==</code> 操作符隐式借用了它自身的操作数：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let c = [1, 2, 3];
</span><span class="boring">let d = vec![1, 2, 3];
</span>let a: &amp;[i32];
let b: &amp;[i32];
<span class="boring">a = &amp;c;
</span><span class="boring">b = &amp;d;
</span>// ...
*a == *b; //译者注：&amp;[i32] 解引用后是一个动态尺寸类型，理论上两个动态尺寸类型上无法比较大小的，但这里因为隐式借用此成为可能
// 等价于下面的形式:
::std::cmp::PartialEq::eq(&amp;*a, &amp;*b);
<span class="boring">}
</span></code></pre></pre>
<p>隐式借用可能会被以下表达式采用：</p>
<ul>
<li><a href="expressions/method-call-expr.html">方法调用</a>表达式中的左操作数。</li>
<li><a href="expressions/field-expr.html">字段</a>表达式中的左操作数。</li>
<li><a href="expressions/call-expr.html">调用表达式</a>中的左操作数。</li>
<li><a href="expressions/array-expr.html#array-and-slice-indexing-expressions">数组索引</a>表达式中的左操作数。</li>
<li><a href="expressions/operator-expr.html#the-dereference-operator">解引用操作符</a>（<code>*</code>）的操作数。</li>
<li><a href="expressions/operator-expr.html#comparison-operators">比较运算</a>的操作数。</li>
<li><a href="expressions/operator-expr.html#compound-assignment-expressions">复合赋值(compound assignment)</a>的左操作数。</li>
</ul>
<h2><a class="header" href="#overloading-traits" id="overloading-traits">Overloading Traits</a></h2>
<h2><a class="header" href="#重载trait" id="重载trait">重载trait</a></h2>
<p>本书后续章节的许多操作符和表达式都可以通过使用 <code>std::ops</code> 或 <code>std::cmp</code> 中的 trait 被其他类型重载。这些 trait 也存在于同名的 <code>core::ops</code> 和 <code>core::cmp</code> 中。</p>
<h2><a class="header" href="#expression-attributes" id="expression-attributes">Expression Attributes</a></h2>
<h2><a class="header" href="#表达式属性" id="表达式属性">表达式属性</a></h2>
<p>只有在少数特定情况下，才允许在表达式之前使用<a href="attributes.html">外部属性</a>：</p>
<ul>
<li>在被当作<a href="statements.html">语句</a>用的表达式之前。</li>
<li><a href="expressions/array-expr.html">数组表达式</a>、<a href="expressions/tuple-expr.html">元组表达式</a>、<a href="expressions/call-expr.html">调用表达式</a>、<a href="expressions/struct-expr.html">元组结构体(tuple-style struct)</a>表达式这些中的元素。<!-- 这些可能已无意中被稳定下来了。参见 https://github.com/rust-lang/rust/issues/32796 和 https://github.com/rust-lang/rust/issues/15701 -->
</li>
<li><a href="expressions/block-expr.html">块表达式</a>的尾部表达式(tail expression)。</li>
</ul>
<!-- 本列表需要和 block-expr.md 保持同步-->
<p>在下面情形之前是不允许的：</p>
<ul>
<li><a href="expressions/range-expr.html">区间(Range)</a>表达式。</li>
<li>二元运算符表达式（<a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators"><em>ArithmeticOrLogicalExpression</em></a>、<a href="expressions/operator-expr.html#comparison-operators"><em>ComparisonExpression</em></a>、<a href="expressions/operator-expr.html#lazy-boolean-operators"><em>LazyBooleanExpression</em></a>、<a href="expressions/operator-expr.html#type-cast-expressions"><em>TypeCastExpression</em></a>、<a href="expressions/operator-expr.html#assignment-expressions"><em>AssignmentExpression</em></a>、<a href="expressions/operator-expr.html#compound-assignment-expressions"><em>CompoundAssignmentExpression</em></a>）。</li>
</ul>
<div class="footnote-definition" id="译者注1"><sup class="footnote-definition-label">1</sup>
<p>通俗理解“求值”，可以理解为：一方面可以从表达式求出值，另一方面可以为表达式赋值。</p>
</div>
<div class="footnote-definition" id="译者注2"><sup class="footnote-definition-label">2</sup>
<p>译者暂时还未用代码测试这种例外情况。</p>
</div>
<h1><a class="header" href="#literal-expressions" id="literal-expressions">Literal expressions</a></h1>
<h1><a class="header" href="#字面量表达式" id="字面量表达式">字面量表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/literal-expr.md">literal-expr.md</a><br />
commit: eb5290329316e96c48c032075f7dbfa56990702b <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LiteralExpression</em> :<br />
      <a href="expressions/../tokens.html#character-literals">CHAR_LITERAL</a><br />
   | <a href="expressions/../tokens.html#string-literals">STRING_LITERAL</a><br />
   | <a href="expressions/../tokens.html#raw-string-literals">RAW_STRING_LITERAL</a><br />
   | <a href="expressions/../tokens.html#byte-literals">BYTE_LITERAL</a><br />
   | <a href="expressions/../tokens.html#byte-string-literals">BYTE_STRING_LITERAL</a><br />
   | <a href="expressions/../tokens.html#raw-byte-string-literals">RAW_BYTE_STRING_LITERAL</a><br />
   | <a href="expressions/../tokens.html#integer-literals">INTEGER_LITERAL</a><br />
   | <a href="expressions/../tokens.html#floating-point-literals">FLOAT_LITERAL</a><br />
   | <a href="expressions/../tokens.html#boolean-literals">BOOLEAN_LITERAL</a></p>
</blockquote>
<p><em>字面量表达式</em>由<a href="expressions/../tokens.html#literals">字面量</a>里讲过的任一形式组成。
它直接描述一个数字、字符、字符串或布尔值。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>&quot;hello&quot;;   // 字符串类型
'5';       // 字符类型
5;         // 整型
<span class="boring">}
</span></code></pre></pre>
<!-- 上面这几个链接从原文来替换时需小心 -->
<h1><a class="header" href="#path-expressions" id="path-expressions">Path expressions</a></h1>
<h1><a class="header" href="#路径表达式" id="路径表达式">路径表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/path-expr.md">path-expr.md</a><br />
commit: eb5290329316e96c48c032075f7dbfa56990702b <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>PathExpression</em> :<br />
      <a href="expressions/../paths.html#paths-in-expressions"><em>PathInExpression</em></a><br />
   | <a href="expressions/../paths.html#qualified-paths"><em>QualifiedPathInExpression</em></a></p>
</blockquote>
<p><a href="expressions/../paths.html">路径</a>被用做表达式上下文时表示局部变量或程序项。
解析为局部变量或静态变量的路径表达式是<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>，其他路径是<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>。
使用 <a href="expressions/../items/static-items.html#mutable-statics"><code>static mut</code></a>变量需在 <a href="expressions/block-expr.html#unsafe-blocks"><code>unsafe</code>块</a>中。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">mod globals {
</span><span class="boring">    pub static STATIC_VAR: i32 = 5;
</span><span class="boring">    pub static mut STATIC_MUT_VAR: i32 = 7;
</span><span class="boring">}
</span><span class="boring">let local_var = 3;
</span>local_var;
globals::STATIC_VAR;
unsafe { globals::STATIC_MUT_VAR };
let some_constructor = Some::&lt;i32&gt;;
let push_integer = Vec::&lt;i32&gt;::push;
let slice_reverse = &lt;[i32]&gt;::reverse;
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#block-expressions" id="block-expressions">Block expressions</a></h1>
<h1><a class="header" href="#块表达式" id="块表达式">块表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/block-expr.md">block-expr.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-6-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>BlockExpression</em> :<br />
   <code>{</code><br />
      <a href="expressions/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
      <em>Statements</em><sup>?</sup><br />
   <code>}</code></p>
<p><em>Statements</em> :<br />
      <a href="expressions/../statements.html"><em>Statement</em></a><sup>+</sup><br />
   | <a href="expressions/../statements.html"><em>Statement</em></a><sup>+</sup> <a href="expressions/../expressions.html"><em>ExpressionWithoutBlock</em></a><br />
   | <a href="expressions/../expressions.html"><em>ExpressionWithoutBlock</em></a></p>
</blockquote>
<p><em>块表达式</em>或<em>块</em>是一个控制流表达式(control flow expression)，同时也是程序项声明和变量声明的匿名空间作用域。
作为控制流表达式，块按顺序执行其非程序项声明的语句组件，最后执行可选的最终表达式(final expression)。
作为一个匿名空间作用域，在本块内声明的程序项只在块本身围成的作用域内有效，而块内由 <code>let</code>语句声明的变量的作用域为下一条语句到块尾。</p>
<p>块的句法规则为：先是一个 <code>{</code>，后跟<a href="expressions/../attributes.html">内部属性</a>，再后是任意条<a href="expressions/../statements.html">语句</a>，再后是一个被称为最终操作数（final operand）的可选表达式，最后是一个 <code>}</code>。</p>
<p>语句之间通常需要后跟分号，但有两个例外：
1、程序项声明语句不需要后跟分号。
2、表达式语句通常需要后面的分号，但它的外层表达式是控制流表达式时不需要。</p>
<p>此外，允许在语句之间使用额外的分号，但是这些分号并不影响语义。</p>
<p>在对块表达式进行求值时，除了程序项声明语句外，每个语句都是按顺序执行的。
如果给出了块尾的可选的最终操作数(final operand)，则最后会执行它。</p>
<p>块的类型是最此块的最终操作数(final operand)的类型，但如果省略了最终操作数，则块的类型为 <code>()</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn fn_call() {}
</span>let _: () = {
    fn_call();
};

let five: i32 = {
    fn_call();
    5
};

assert_eq!(5, five);
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：作为控制流表达式，如果块表达式是一个表达式语句的外层表达式，则该块表达式的预期类型为 <code>()</code>，除非该块后面紧跟着一个分号。</p>
</blockquote>
<p>块总是<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>，并会在值表达式上下文中对最后的那个操作数进行求值。</p>
<blockquote>
<p><strong>注意</strong>：如果确实有需要，块可以用于强制移动值。
例如，下面的示例在调用 <code>consume_self</code> 时失败，因为结构体已经在之前的块表达式里被从 <code>s</code> 里移出了。</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Struct;

impl Struct {
    fn consume_self(self) {}
    fn borrow_self(&amp;self) {}
}

fn move_by_block_expression() {
    let s = Struct;

    // 将值从块表达式里的 `s` 里移出。
    (&amp;{ s }).borrow_self();

    // 执行失败，因为 `s` 里的值已经被移出。
    s.consume_self();
}
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<h2><a class="header" href="#async-blocks" id="async-blocks"><code>async</code> blocks</a></h2>
<h2><a class="header" href="#async块" id="async块"><code>async</code>块</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>AsyncBlockExpression</em> :<br />
   <code>async</code> <code>move</code><sup>?</sup> <em>BlockExpression</em></p>
</blockquote>
<p>*异步块(async block)*是求值为 <em>future</em> 的块表达式的一个变体。
块的最终表达式（如果存在）决定了 future 的结果值。（译者注：单词 future 对应中文为“未来”。原文可能为了双关的行文效果，经常把作为类型的 future 和字面意义上的 future 经常混用，所以译者基本保留此单词不翻译，特别强调“未来”的意义时也会加上其英文单词。）</p>
<p>执行一个异步块类似于执行一个闭包表达式：它的即时效果是生成并返回一个匿名类型。
类似闭包返回的类型实现了一个或多个 <a href="https://doc.rust-lang.org/std/ops/trait.Fn.html"><code>std::ops::Fn</code></a> trait，异步块返回的类型实现了 <a href="https://doc.rust-lang.org/std/future/trait.Future.html"><code>std::future::Future</code></a> trait。
此类型的实际数据格式规范还未确定下来。</p>
<blockquote>
<p><strong>注意：</strong> rustc 生成的 future类型大致相当于一个枚举，rustc 为这个 future 的每个 <code>await</code>点生成一个此枚举的变体，其中每个变体都存储了对应点再次恢复执行时需要的数据。</p>
</blockquote>
<blockquote>
<p><strong>版本差异</strong>: 异步块从 Rust 2018 版才开始可用。</p>
</blockquote>
<h3><a class="header" href="#capture-modes" id="capture-modes">Capture modes</a></h3>
<h3><a class="header" href="#捕获方式" id="捕获方式">捕获方式</a></h3>
<p>异步块使用与闭包相同的<a href="expressions/../types/closure.html#capture-modes">捕获方式</a>从其环境中捕获变量。
跟闭包一样，当编写 <code>async { .. }</code> 时，每个变量的捕获方式将从该块里的内容中推断出来。
而 <code>async move { .. }</code> 类型的异步块将把所有需要捕获的变量使用移动语义移入(move)到相应的结果 future 中。</p>
<h3><a class="header" href="#async-context" id="async-context">Async context</a></h3>
<h3><a class="header" href="#异步上下文" id="异步上下文">异步上下文</a></h3>
<p>因为异步块构造了一个 future，所以它们定义了一个<strong>async上下文</strong>，这个上下文可以相应地包含 <a href="expressions/await-expr.html"><code>await</code>表达式</a>。
异步上下文是由异步块和异步函数的函数体建立的，它们的语义是依照异步块定义的。</p>
<h3><a class="header" href="#control-flow-operators" id="control-flow-operators">Control-flow operators</a></h3>
<h3><a class="header" href="#控制流操作符" id="控制流操作符">控制流操作符</a></h3>
<p>异步块的作用类似于函数边界，或者更类似于闭包。
因此 <code>?</code>操作符和 返回(<code>return</code>)表达式也都能影响 future 的输出，且不会影响封闭它的函数或其他上下文。
也就是说，future 的输出跟闭包将其中的 <code>return &lt;expr&gt;</code> 的表达式 <code>&lt;expr&gt;</code> 的计算结果作为未来的输出的做法是一样的。
类似地,如果 <code>&lt;expr&gt;?</code> 传播(propagate)一个错误，这个错误也会被 future 在未来的某个时候作为返回结果被传播出去。</p>
<p>最后，关键字 <code>break</code> 和 <code>continue</code> 不能用于从异步块中跳出分支。
因此，以下内容是非法的：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>loop {
    async move {
        break; // 这将打破循环。
    }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#unsafe-blocks" id="unsafe-blocks"><code>unsafe</code> blocks</a></h2>
<h2><a class="header" href="#非安全unsafe块" id="非安全unsafe块">非安全(<code>unsafe</code>)块</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong>\23672971a16c69ea894bef24992b74912cfe5d25e` 的信息_</p>
</blockquote>
<p>可以在代码块前面加上关键字 <code>unsafe</code> 以允许<a href="expressions/../unsafety.html">非安全操作</a>。
例如：</p>
<pre><pre class="playground"><code class="language-rust23672971a16c69ea894bef24992b74912cfe5d25 edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>在以下上下文中，允许在块表达式的左括号之后直接使用[内部属性][inner attributes]：

* [函数][function]和[方法][method]的代码体。
* 循环体（[`loop`], [`while`], [`while let`], 和 [`for`]）。
* 被用作[语句][statement]的块表达式。
* 块表达式作为[数组表达式][array expressions]、[元组表达式][tuple expressions]、[调用表达式][call expressions]、[元组结构体][struct]表达式和[枚举变体][enum variant]表达式的元素。
* 作为另一个块表达式的尾部表达式(tail expression)的块表达式。
&lt;!-- 本列表需要和 expressions.md 保持同步 --&gt;

在块表达式上有意义的属性有 [`cfg`] 和 [lint检查类属性][the lint check attributes]。

例如，下面这个函数在 unix 平台上返回 `true`，在其他平台上返回 `false`。

```rust
fn is_unix_platform() -&gt; bool {
    #[cfg(unix)] { true }
    #[cfg(not(unix))] { false }
}
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#操作符运算符表达式" id="操作符运算符表达式">操作符/运算符表达式</a></h1>
<h1><a class="header" href="#operator-expressions" id="operator-expressions">Operator expressions</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/operator-expr.md">operator-expr.md</a><br />
commit: 0b7f340e8963eccac662f97cb679855f043a658f <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>OperatorExpression</em> :<br />
      <a href="expressions/operator-expr.html#borrow-operators"><em>BorrowExpression</em></a><br />
   | <a href="expressions/operator-expr.html#the-dereference-operator"><em>DereferenceExpression</em></a><br />
   | <a href="expressions/operator-expr.html#the-question-mark-operator"><em>ErrorPropagationExpression</em></a><br />
   | <a href="expressions/operator-expr.html#negation-operators"><em>NegationExpression</em></a><br />
   | <a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators"><em>ArithmeticOrLogicalExpression</em></a><br />
   | <a href="expressions/operator-expr.html#comparison-operators"><em>ComparisonExpression</em></a><br />
   | <a href="expressions/operator-expr.html#lazy-boolean-operators"><em>LazyBooleanExpression</em></a><br />
   | <a href="expressions/operator-expr.html#type-cast-expressions"><em>TypeCastExpression</em></a><br />
   | <a href="expressions/operator-expr.html#assignment-expressions"><em>AssignmentExpression</em></a><br />
   | <a href="expressions/operator-expr.html#compound-assignment-expressions"><em>CompoundAssignmentExpression</em></a></p>
</blockquote>
<p>操作符是 Rust 语言为其内建类型定义的。
本文后面的许多操作符都可以使用 <code>std::ops</code> 或 <code>std::cmp</code> 中的 trait 进行重载。</p>
<h2><a class="header" href="#溢出" id="溢出">溢出</a></h2>
<h2><a class="header" href="#overflow" id="overflow">Overflow</a></h2>
<p>在 debug模式下编译整数运算时，如果发生溢出，会触发 panic。
可以使用命令行参数 <code>-C debug-assertions</code> 和 <code>-C overflow-checks</code> 设置编译器标志位来更直接地控制这个溢出过程。
以下情况被认为是溢出：</p>
<ul>
<li>当 <code>+</code>、<code>*</code> 或 <code>-</code> 创建的值大于当前类型可存储的最大值或小于最小值。这包括任何有符号整型的最小值上的一元运算符 <code>-</code>。</li>
<li>使用 <code>/</code> 或 <code>%</code>，其中左操作数是某类有符号整型的最小整数，右操作数是 <code>-1</code>。注意，即使由于历史原因禁用了 <code>-C overflow-checks</code>选项，这些检查仍会发生。</li>
<li>使用 <code>&lt;&lt;</code> 或 <code>&gt;&gt;</code>，其中右操作数大于或等于左操作数类型的 bit 数，或右操作数为负数。</li>
</ul>
<h2><a class="header" href="#借用操作符运算符" id="借用操作符运算符">借用操作符/运算符</a></h2>
<h2><a class="header" href="#borrow-operators" id="borrow-operators">Borrow operators</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>BorrowExpression</em> :<br />
      (<code>&amp;</code>|<code>&amp;&amp;</code>) <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | (<code>&amp;</code>|<code>&amp;&amp;</code>) <code>mut</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><code>&amp;</code>（共享借用）和 <code>&amp;mut</code>（可变借用）运算符是一元前缀运算符。
当应用于<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>上时，此表达式生成指向值所在的内存位置的引用（指针）。
在引用存续期间，该内存位置也被置于借出状态。
对于共享借用（<code>&amp;</code>），这意味着该位置可能不会发生变化，但可能会被再次读取或共享。
对于可变借用（<code>&amp;mut</code>），在借用到期之前，不能以任何方式访问该位置。<code>&amp;mut</code> 在可变位置表达式上下文中会对其操作数求值。
如果 <code>&amp;</code> 或 <code>&amp;mut</code> 运算符应用于<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>上，则会创建一个<a href="expressions/../expressions.html#temporaries">临时值</a>。</p>
<p>这类操作符不能重载。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>{
    // 将创建一个存值为7的临时位置，该该临时位置在此作用域内持续存在
    let shared_reference = &amp;7;
}
let mut array = [-2, 3, 9];
{
    // 在当前作用域内可变借用了 `array`。那 `array` 就只能通过 `mutable_reference` 来使用。
    let mutable_reference = &amp;mut array;
}
<span class="boring">}
</span></code></pre></pre>
<p>尽管 <code>&amp;&amp;</code> 是一个单一 token（<a href="expressions/operator-expr.html#lazy-boolean-operators">惰性与(<code>and</code>)操作符</a>)，但在借用表达式(borrow expressions)上下文中使用时，它是作为两个借用操作符用的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 意义相同：
let a = &amp;&amp;  10;
let a = &amp; &amp; 10;

// 意义相同：
let a = &amp;&amp;&amp;&amp;  mut 10;
let a = &amp;&amp; &amp;&amp; mut 10;
let a = &amp; &amp; &amp; &amp; mut 10;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#解引用操作符" id="解引用操作符">解引用操作符</a></h2>
<h2><a class="header" href="#the-dereference-operator" id="the-dereference-operator">The dereference operator</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>DereferenceExpression</em> :<br />
   <code>*</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><code>*</code>（解引用）操作符也是一元前缀操作符。当应用于<a href="expressions/../types/pointer.html">指针</a>上时，它表示该指针指向的内存位置。
如果表达式的类型为 <code>&amp;mut T</code> 或 <code>*mut T</code>，并且该表达式是局部变量、局部变量的（内嵌）字段、或是可变的<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>，则它代表的内存位置可以被赋值。解引用原始指针需要在非安全(<code>unsafe</code>)块才能进行。</p>
<p>在<a href="expressions/../expressions.html#mutability">不可变位置表达式上下文</a>中对非指针类型作 <code>*x</code> 相当于执行 <code>*std::ops::Deref::deref(&amp;x)</code>；同样的，在可变位置表达式上下文中这个动作就相当于执行 <code>*std::ops::DerefMut::deref_mut(&amp;mut x)</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = &amp;7;
assert_eq!(*x, 7);
let y = &amp;mut 9;
*y = 11;
assert_eq!(*y, 11);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#问号操作符" id="问号操作符">问号操作符</a></h2>
<h2><a class="header" href="#the-question-mark-operator" id="the-question-mark-operator">The question mark operator</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ErrorPropagationExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>?</code></p>
</blockquote>
<p>问号操作符（<code>?</code>）解包(unwrap)有效值或返回错误值，并将它们传播(propagate)给调用函数。
问号操作符（<code>?</code>）是一个一元后缀操作符，只能应用于类型 <code>Result&lt;T, E&gt;</code> 和 <code>Option&lt;T&gt;</code>。</p>
<p>当应用在 <code>Result&lt;T, E&gt;</code> 类型的值上时，它可以传播错误。
如果值是 <code>Err(e)</code>，那么它实际上将从此操作符所在的函数体或闭包中返回 <code>Err(From::from(e))</code>。
如果应用到 <code>Ok(x)</code>，那么它将解包此值以求得 <code>x</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::num::ParseIntError;
</span>fn try_to_parse() -&gt; Result&lt;i32, ParseIntError&gt; {
    let x: i32 = &quot;123&quot;.parse()?; // x = 123
    let y: i32 = &quot;24a&quot;.parse()?; // 立即返回一个 Err()
    Ok(x + y)                    // 不会执行到这里
}

let res = try_to_parse();
println!(&quot;{:?}&quot;, res);
<span class="boring">assert!(res.is_err())
</span><span class="boring">}
</span></code></pre></pre>
<p>当应用到 <code>Option&lt;T&gt;</code> 类型的值时，它向调用者传播错误 <code>None</code>。
如果它应用的值是 <code>None</code>，那么它将返回 <code>None</code>。
如果应用的值是 <code>Some(x)</code>，那么它将解包此值以求得 <code>x</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn try_option_some() -&gt; Option&lt;u8&gt; {
    let val = Some(1)?;
    Some(val)
}
assert_eq!(try_option_some(), Some(1));

fn try_option_none() -&gt; Option&lt;u8&gt; {
    let val = None?;
    Some(val)
}
assert_eq!(try_option_none(), None);
<span class="boring">}
</span></code></pre></pre>
<p>操作符 <code>?</code> 不能被重载。</p>
<h2><a class="header" href="#取反运算符" id="取反运算符">取反运算符</a></h2>
<h2><a class="header" href="#negation-operators" id="negation-operators">Negation operators</a></h2>
<blockquote>
<p><strong><sup>语法</sup></strong><br />
<em>NegationExpression</em> :<br />
      <code>-</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <code>!</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>这是最后两个一元运算符。
下表总结了它们用在基本类型上的表现，同时指出其他类型要重载这些操作符需要实现的 trait。
记住，有符号整数总是用二进制补码形式表示。
所有这些运算符的操作数都在<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式上下文</a>中被求值，所以这些操作数的值会被移走或复制。</p>
<table><thead><tr><th>符号</th><th>整数</th><th><code>bool</code></th><th>浮点数</th><th>用于重载的 trait</th></tr></thead><tbody>
<tr><td><code>-</code></td><td>符号取反*</td><td></td><td>符号取反</td><td><code>std::ops::Neg</code></td></tr>
<tr><td><code>!</code></td><td>按位取反</td><td><a href="expressions/../types/boolean.html#logical-not">逻辑非</a></td><td></td><td><code>std::ops::Not</code></td></tr>
</tbody></table>
<p>* 仅适用于有符号整数类型。</p>
<p>下面是这些运算符的一些示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = 6;
assert_eq!(-x, -6);
assert_eq!(!x, -7);
assert_eq!(true, !false);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#算术和逻辑二元运算符" id="算术和逻辑二元运算符">算术和逻辑二元运算符</a></h2>
<h2><a class="header" href="#arithmetic-and-logical-binary-operators" id="arithmetic-and-logical-binary-operators">Arithmetic and Logical Binary Operators</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ArithmeticOrLogicalExpression</em> :<br />
      <a href="expressions/../expressions.html"><em>Expression</em></a> <code>+</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>-</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>*</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>/</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>%</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&amp;</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>|</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>^</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&lt;&lt;</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&gt;&gt;</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>二元运算符表达式都用中缀表示法(infix notation)书写。
下表总结了算术和逻辑二元运算符在原生类型(primitive type)上的行为，同时指出其他类型要重载这些操作符需要实现的 trait。
记住，有符号整数总是用二进制补码形式表示。
所有这些运算符的操作数都在<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式上下文</a>中求值，因此这些操作数的值会被移走或复制。</p>
<table><thead><tr><th>符号</th><th>整数</th><th><code>bool</code></th><th>浮点数</th><th>用于重载此运算符的 trait</th><th>用于重载此运算符的复合赋值(Compound Assignment) Trait</th></tr></thead><tbody>
<tr><td><code>+</code></td><td>加法</td><td></td><td>加法</td><td><code>std::ops::Add</code></td><td><code>std::ops::AddAssign</code></td></tr>
<tr><td><code>-</code></td><td>减法</td><td></td><td>减法</td><td><code>std::ops::Sub</code></td><td><code>std::ops::SubAssign</code></td></tr>
<tr><td><code>*</code></td><td>乘法</td><td></td><td>乘法</td><td><code>std::ops::Mul</code></td><td><code>std::ops::MulAssign</code></td></tr>
<tr><td><code>/</code></td><td>除法*</td><td></td><td>取余</td><td><code>std::ops::Div</code></td><td><code>std::ops::DivAssign</code></td></tr>
<tr><td><code>%</code></td><td>取余**</td><td></td><td>Remainder</td><td><code>std::ops::Rem</code></td><td><code>std::ops::RemAssign</code></td></tr>
<tr><td><code>&amp;</code></td><td>按位与</td><td><a href="expressions/../types/boolean.html#logical-and">逻辑与</a></td><td></td><td><code>std::ops::BitAnd</code></td><td><code>std::ops::BitAndAssign</code></td></tr>
<tr><td><code>|</code></td><td>按位或</td><td><a href="expressions/../types/boolean.html#logical-or">逻辑或</a></td><td></td><td><code>std::ops::BitOr</code></td><td><code>std::ops::BitOrAssign</code></td></tr>
<tr><td><code>^</code></td><td>按位异或</td><td><a href="expressions/../types/boolean.html#logical-xor">逻辑异或</a></td><td></td><td><code>std::ops::BitXor</code></td><td><code>std::ops::BitXorAssign</code></td></tr>
<tr><td><code>&lt;&lt;</code></td><td>左移位</td><td></td><td></td><td><code>std::ops::Shl</code></td><td><code>std::ops::ShlAssign</code></td></tr>
<tr><td><code>&gt;&gt;</code></td><td>右移位***</td><td></td><td></td><td><code>std::ops::Shr</code></td><td><code>std::ops::ShrAssign</code></td></tr>
</tbody></table>
<p>* 整数除法趋零取整。</p>
<p>** Rust使用由<a href="https://en.wikipedia.org/wiki/Modulo_operation#Variants_of_the_definition">截断除法</a>定义的求宇运算。也就是 <code>余数=被除数%除数</code>，其中余数将与被除数的符号一致。</p>
<p>*** 有符号整数类型算术右移位，无符号整数类型逻辑右移位。</p>
<p>下面是使用这些操作符的示例:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>assert_eq!(3 + 6, 9);
assert_eq!(5.5 - 1.25, 4.25);
assert_eq!(-5 * 14, -70);
assert_eq!(14 / 3, 4);
assert_eq!(100 % 7, 2);
assert_eq!(0b1010 &amp; 0b1100, 0b1000);
assert_eq!(0b1010 | 0b1100, 0b1110);
assert_eq!(0b1010 ^ 0b1100, 0b110);
assert_eq!(13 &lt;&lt; 3, 104);
assert_eq!(-10 &gt;&gt; 2, -3);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#比较运算符" id="比较运算符">比较运算符</a></h2>
<h2><a class="header" href="#comparison-operators" id="comparison-operators">Comparison Operators</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ComparisonExpression</em> :<br />
      <a href="expressions/../expressions.html"><em>Expression</em></a> <code>==</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>!=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&gt;</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&lt;</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&gt;=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&lt;=</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>Rust 还为原生类型以及标准库中的多种类型都定义了比较运算符。
链式比较运算时需要借助圆括号，例如，表达式 <code>a == b == c</code> 是无效的，（但如果逻辑允许）可以写成 <code>(a == b) == c</code>。</p>
<p>与算术运算符和逻辑运算符不同，重载这些运算符的 trait 通常用于显示/约定如何比较一个类型，并且还很可能会假定使用这些 trait 作为约束条件的函数定义了实际的比较逻辑。
其实标准库中的许多函数和宏都使用了这个假定（尽管不能确保这些假定的安全性）。
与上面的算术和逻辑运算符不同，这些运算符会隐式地对它们的操作数执行共享借用，并在<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式上下文</a>中对它们进行求值：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let a = 1;
</span><span class="boring">let b = 1;
</span>a == b;
// 等价于：
::std::cmp::PartialEq::eq(&amp;a, &amp;b);
<span class="boring">}
</span></code></pre></pre>
<p>这意味着不需要将值从操作数移出(moved out of)。</p>
<table><thead><tr><th>符号</th><th>含义</th><th>须重载方法</th></tr></thead><tbody>
<tr><td><code>==</code></td><td>等于</td><td><code>std::cmp::PartialEq::eq</code></td></tr>
<tr><td><code>!=</code></td><td>不等于</td><td><code>std::cmp::PartialEq::ne</code></td></tr>
<tr><td><code>&gt;</code></td><td>大于</td><td><code>std::cmp::PartialOrd::gt</code></td></tr>
<tr><td><code>&lt;</code></td><td>小于</td><td><code>std::cmp::PartialOrd::lt</code></td></tr>
<tr><td><code>&gt;=</code></td><td>大于或等于</td><td><code>std::cmp::PartialOrd::ge</code></td></tr>
<tr><td><code>&lt;=</code></td><td>小于或等于</td><td><code>std::cmp::PartialOrd::le</code></td></tr>
</tbody></table>
<p>下面是使用比较运算符的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>assert!(123 == 123);
assert!(23 != -12);
assert!(12.5 &gt; 12.2);
assert!([1, 2, 3] &lt; [1, 3, 4]);
assert!('A' &lt;= 'B');
assert!(&quot;World&quot; &gt;= &quot;Hello&quot;);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#短路布尔运算符" id="短路布尔运算符">短路布尔运算符</a></h2>
<h2><a class="header" href="#lazy-boolean-operators" id="lazy-boolean-operators">Lazy boolean operators</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LazyBooleanExpression</em> :<br />
      <a href="expressions/../expressions.html"><em>Expression</em></a> <code>||</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&amp;&amp;</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p>运算符 <code>||</code> 和 <code>&amp;&amp;</code> 可以应用在布尔类型的操作数上。
运算符 <code>||</code> 表示逻辑“或”，运算符 <code>&amp;&amp;</code> 表示逻辑“与”。
它们与 <code>|</code> 和 <code>&amp;</code> 的不同之处在于，只有在左操作数尚未确定表达式的结果时，才计算右操作数。
也就是说，<code>||</code> 只在左操作数的计算结果为 <code>false</code> 时才计算其右操作数，而只有在计算结果为 <code>true</code> 时才计算 <code>&amp;&amp;</code> 的操作数。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = false || true; // true
let y = false &amp;&amp; panic!(); // false, 不会计算 `panic!()`
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#类型转换表达式" id="类型转换表达式">类型转换表达式</a></h2>
<h2><a class="header" href="#type-cast-expressions" id="type-cast-expressions">Type cast expressions</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TypeCastExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>as</code> <a href="expressions/../types.html#type-expressions"><em>TypeNoBounds</em></a></p>
</blockquote>
<p>类型转换表达式用二元运算符 <code>as</code> 表示。</p>
<p>执行类型转换(<code>as</code>)表达式将左侧的值显式转换为右侧的类型。</p>
<p>类型转换(<code>as</code>)表达式的一个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn sum(values: &amp;[f64]) -&gt; f64 { 0.0 }
</span><span class="boring">fn len(values: &amp;[f64]) -&gt; i32 { 0 }
</span>fn average(values: &amp;[f64]) -&gt; f64 {
    let sum: f64 = sum(values);
    let size: f64 = len(values) as f64;
    sum / size
}
<span class="boring">}
</span></code></pre></pre>
<p><code>as</code> 可用于显式执行<a href="expressions/../type-coercions.html">自动强转(coercions)</a>，以及下列形式的强制转换。
任何不符合强转规则或不在下表中的转换都会导致编译器报错。
下表中 <code>*T</code> 代表 <code>*const T</code> 或 <code>*mut T</code>。<code>m</code> 引用类型中代表可选的 <code>mut</code> 或指针类型中的 <code>mut</code> 或 <code>const</code>。</p>
<table><thead><tr><th><code>e</code> 的类型</th><th><code>U</code></th><th>通过 <code>e as U</code> 执行转换</th></tr></thead><tbody>
<tr><td>整型或浮点型</td><td>整型或浮点型</td><td>数字转换</td></tr>
<tr><td>类C(C-like)枚举</td><td>整型</td><td>枚举转换</td></tr>
<tr><td><code>bool</code> 或 <code>char</code></td><td>整型</td><td>原生类型到整型的转换</td></tr>
<tr><td><code>u8</code></td><td><code>char</code></td><td><code>u8</code> 到 <code>char</code> 的转换</td></tr>
<tr><td><code>*T</code></td><td><code>*V</code> where <code>V: Sized</code> *</td><td>指针到指针的转换</td></tr>
<tr><td><code>*T</code> where <code>T: Sized</code></td><td>数字型(Numeric type)</td><td>指针到地址的转换</td></tr>
<tr><td>整型</td><td><code>*V</code> where <code>V: Sized</code></td><td>地址到指针的转换</td></tr>
<tr><td><code>&amp;m₁ T</code></td><td><code>*m₂ T</code> **</td><td>引用到指针的转换</td></tr>
<tr><td><code>&amp;m₁ [T; n]</code></td><td><code>*m₂ T</code> **</td><td>数组到指针的转换</td></tr>
<tr><td><a href="expressions/../types/function-item.html">函数项</a></td><td><a href="expressions/../types/function-pointer.html">函数指针</a></td><td>函数到函数指针的转换</td></tr>
<tr><td><a href="expressions/../types/function-item.html">函数项</a></td><td><code>*V</code> where <code>V: Sized</code></td><td>函数到指针的转换</td></tr>
<tr><td><a href="expressions/../types/function-item.html">函数项</a></td><td>整型</td><td>函数到地址的转换</td></tr>
<tr><td><a href="expressions/../types/function-pointer.html">函数指针</a></td><td><code>*V</code> where <code>V: Sized</code></td><td>函数指针到指针的转换</td></tr>
<tr><td><a href="expressions/../types/function-pointer.html">函数指针</a></td><td>整型</td><td>函数指针到地址的转换</td></tr>
<tr><td>闭包 ***</td><td>函数指针</td><td>闭包到函数指针的转换</td></tr>
</tbody></table>
<p>* 或者 <code>T</code>和<code>V</code> 也可以都是兼容的 unsized 类型，例如，两个都是切片，或者都是同一种 trait对象。</p>
<p>** 仅当 <code>m₁</code> 是 <code>mut</code> 或 <code>m₂</code> 是 <code>const</code>时， 可变(<code>mut</code>)引用到 <code>const</code>指针才会被允许。</p>
<p>*** 仅适用于不捕获（遮蔽(close over)）任何环境变量的闭包。</p>
<h3><a class="header" href="#语义" id="语义">语义</a></h3>
<h3><a class="header" href="#semantics" id="semantics">Semantics</a></h3>
<h4><a class="header" href="#数字转换" id="数字转换">数字转换</a></h4>
<h4><a class="header" href="#numeric-cast" id="numeric-cast">Numeric cast</a></h4>
<ul>
<li>在两个尺寸(size)相同的整型数值（例如 i32 -&gt; u32）之间进行转换是一个空操作(no-op) （Rust 使用2的补码表示定长整数的负值）</li>
<li>从一个较大尺寸的整型转换为较小尺寸的整型（例如 u32 -&gt; u8）将会采用截断(truncate)算法 <sup class="footnote-reference"><a href="#译者注">1</a></sup></li>
<li>从较小尺寸的整型转换为较大尺寸的整型（例如 u8 -&gt; u32）将
<ul>
<li>如果源数据是无符号的，则进行零扩展(zero-extend)</li>
<li>如果源数据是有符号的，则进行符号扩展(sign-extend)</li>
</ul>
</li>
<li>从浮点数转换为整型将使浮点数趋零取整(round the float towards zero)
<ul>
<li><code>NaN</code> 将返回 <code>0</code></li>
<li>大于转换到的整型类型的最大值时（包括 <code>INFINITY</code>），取该整型类型的最大值。</li>
<li>小于转换到的整型类型的最小值时（包括 <code>INFINITY</code>），取该整型类型的最小值。</li>
</ul>
</li>
<li>从整数强制转换为浮点数将产生最接近的浮点数 *
<ul>
<li>如有必要，舍入采用 <code>roundTiesToEven</code>模式 ***</li>
<li>在溢出时，将会产生该浮点型的常量 Infinity(∞)（与输入符号相同）</li>
<li>注意：对于当前的数值类型集，溢出只会发生在 <code>u128 as f32</code> 这种转换形式，且数字大于或等于 <code>f32::MAX + (0.5 ULP)</code> 时。</li>
</ul>
</li>
<li>从 f32 到 f64 的转换是无损转换</li>
<li>从 f64 到 f32 的转换将产生最接近的 f32 **
<ul>
<li>如有必要，舍入采用 <code>roundTiesToEven</code>模式 ***</li>
<li>在溢出时，将会产生 f32 的常量 Infinity(∞)（与输入符号相同）
* 如果硬件本身不支持这种舍入模式和溢出行为，那么这些整数到浮点型的转换可能会比预期的要慢。</li>
</ul>
</li>
</ul>
<p>** 如果硬件本身不支持这种舍入模式和溢出行为，那么这些 f64 到 f32 的转换可能会比预期的要慢。</p>
<p>*** 按照 IEEE 754-2008§4.3.1 的定义：选择最接近的浮点数，如果恰好在两个浮点数中间，则优先选择最低有效位为偶数的那个。</p>
<h4><a class="header" href="#enum-cast" id="enum-cast">Enum cast</a></h4>
<h4><a class="header" href="#枚举转换" id="枚举转换">枚举转换</a></h4>
<p>可将枚举类型转换为其判别值，然后在必要时可以使用数字类型转换。</p>
<h4><a class="header" href="#primitive-to-integer-cast" id="primitive-to-integer-cast">Primitive to integer cast</a></h4>
<h4><a class="header" href="#原生类型到整型" id="原生类型到整型">原生类型到整型</a></h4>
<ul>
<li><code>false</code> 转换为 <code>0</code>，<code>true</code> 转换为 <code>1</code>。</li>
<li><code>char</code> 转换为字符码点，然后在必要时可以使用数字类型转换。</li>
</ul>
<h4><a class="header" href="#u8-to-char-cast" id="u8-to-char-cast"><code>u8</code> to <code>char</code> cast</a></h4>
<h4><a class="header" href="#u8-到-char" id="u8-到-char"><code>u8</code> 到 <code>char</code></a></h4>
<p>把为 <code>char</code> 的字符代码点的 <code>u8</code> 值转换为 <code>char</code></p>
<h4><a class="header" href="#pointer-to-address-cast" id="pointer-to-address-cast">Pointer to address cast</a></h4>
<h4><a class="header" href="#指针到地址" id="指针到地址">指针到地址</a></h4>
<p>把原始指针转换为整数将产生此指针指向的内存的机器地址。
如果被转换出的整数类型尺寸小于指针类型的位宽，地址可能会被截断；可以使用类型 <code>usize</code> 来避免这种情况。</p>
<h4><a class="header" href="#address-to-pointer-cast" id="address-to-pointer-cast">Address to pointer cast</a></h4>
<h4><a class="header" href="#地址到指针" id="地址到指针">地址到指针</a></h4>
<p>从整数转换为原始指针会将整数解释为内存地址，并生成一个引用该内存地址的指针。</p>
<div class="warning">
<p>警告：
这将与 Rust内存模型交互，需要指出的是该模型仍在开发中。
即便是按位转换后是一个有效的指针，但这种从转换中生成的指针可能会受到一些额外的限制。如果不遵循别名规则，那么解引用这样的指针可能是<a href="expressions/../behavior-considered-undefined.html">未定义行为</a>。</p>
</div>
<p>一个常见的健壮的地址转换算法的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut values: [i32; 2] = [1, 2];
let p1: *mut i32 = values.as_mut_ptr();
let first_address = p1 as usize;
let second_address = first_address + 4; // 4 == size_of::&lt;i32&gt;()
let p2 = second_address as *mut i32;
unsafe {
    *p2 += 1;
}
assert_eq!(values[1], 3);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#赋值表达式" id="赋值表达式">赋值表达式</a></h2>
<h2><a class="header" href="#assignment-expressions" id="assignment-expressions">Assignment expressions</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>AssignmentExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>=</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>赋值表达式</em>会把某个值移入到一个特定的位置。</p>
<p><em>赋值表达式</em>由一个<a href="expressions/../expressions.html#mutability">可变</a> <a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>（就是<em>被赋值的位置操作数</em>）后跟等号（<code>=</code>）和<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>（就是被赋值的值操作数）组成。</p>
<p>与其他位置操作数不同，赋值位置操作数必须是一个位置表达式。
试图使用值表达式将导致编译器报错，而不是将其提升转换为临时位置。</p>
<p>赋值表达式要先计算它的操作数。
赋值的值操作数先被求值，然后是赋值的位置操作数。</p>
<blockquote>
<p><strong>注意</strong>：此表达式与其他表达式的求值顺序不同，此表达式的右操作数在左操作数之前被求值。</p>
</blockquote>
<p>对赋值表达的位置表达式求值时会先<a href="expressions/../destructors.html">销毁(drop)</a>此位置（如果是未初始化的局部变量或未初始化的局部变量的字段则不会启动这步析构操作），然后将赋值值<a href="expressions/../expressions.html#moved-and-copied-types">复制(copy)或移动(move)</a>到此位置中。</p>
<p>赋值表达式总是会生成<a href="expressions/../types/tuple.html">单元类型值</a>。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut x = 0;
let y = 0;
x = y;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#复合赋值表达式" id="复合赋值表达式">复合赋值表达式</a></h2>
<h2><a class="header" href="#compound-assignment-expressions" id="compound-assignment-expressions">Compound assignment expressions</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>CompoundAssignmentExpression</em> :<br />
      <a href="expressions/../expressions.html"><em>Expression</em></a> <code>+=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>-=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>*=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>/=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>%=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&amp;=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>|=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>^=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&lt;&lt;=</code> <a href="expressions/../expressions.html"><em>Expression</em></a><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>&gt;&gt;=</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>复合赋值表达式</em>将算术符（以及二进制逻辑操作符）与赋值表达式相结合在一起使用。</p>
<p>比如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut x = 5;
x += 1;
assert!(x == 6);
<span class="boring">}
</span></code></pre></pre>
<p>复合赋值的句法是<a href="expressions/../expressions.html#mutability">可变</a> <a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>（<em>被赋值操作数</em>），然后是一个操作符再后跟一个 <code>=</code>（这两个符号共同作为一个单独的 token），最后是一个<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>（也叫被复合修改操作数(modifying operand)）。</p>
<p>与其他位置操作数不同，被赋值的位置操作数必须是一个位置表达式。
试图使用值表达式将导致编译器报错，而不是将其提升转换为临时位置。</p>
<p>复合赋值表达式的求值取决于操作符的类型。</p>
<p>如果复合赋值表达式了两个操作数的类型都是原生类型，则首先对被复合修改操作数进行求值，然后再对被赋值操作数求值。
最后将被赋值操作数的位置值设置为原被赋值操作数的值和复合修改操作数执行运算后的值。</p>
<blockquote>
<p><strong>注意</strong>：此表达式与其他表达式的求值顺序不同，此表达式的右操作数在左操作数之前被求值。</p>
</blockquote>
<p>此外，这个表达式是调用操作符重载复合赋值trait 的函数的语法糖（见本章前面的表格）。
被赋值操作数必须是可变的。</p>
<p>例如，下面 <code>example</code>函数中的两个表达式语句是等价的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Addable;
</span><span class="boring">use std::ops::AddAssign;
</span>
impl AddAssign&lt;Addable&gt; for Addable {
    /* */
<span class="boring">fn add_assign(&amp;mut self, other: Addable) {}
</span>}

fn example() {
<span class="boring">let (mut a1, a2) = (Addable, Addable);
</span>  a1 += a2;

<span class="boring">let (mut a1, a2) = (Addable, Addable);
</span>  AddAssign::add_assign(&amp;mut a1, a2);
}
<span class="boring">}
</span></code></pre></pre>
<p>与赋值表达式一样，复合赋值表达式也总是会生成<a href="expressions/../types/tuple.html">单元类型值</a>。</p>
<div class="warning">
<p>警告：复合赋值表达式的操作数的求值顺序取决于操作数的类型：对于原生类型，右边操作数将首先被求值，而对于非原生类型，左边操作数将首先被求值。
建议尽量不要编写依赖于复合赋值表达式中操作数的求值顺序的代码。请参阅<a href="https://github.com/rust-lang/rust/blob/master/src/test/ui/expr/compound-assignment/eval-order.rs">这里的测试</a>以获得使用此依赖项的示例。</p>
</div>
<div class="footnote-definition" id="译者注"><sup class="footnote-definition-label">1</sup>
<p>截断，即一个值范围较大的变量A转换为值范围较小的变量B，如果超出范围，则将A减去B的区间长度。例如，128超出了i8类型的范围（-128,127），截断之后的值等于128-256=-128。</p>
</div>
<!-- 上面这几个链接从原文来替换时需小心 -->
<h1><a class="header" href="#grouped-expressions" id="grouped-expressions">Grouped expressions</a></h1>
<h1><a class="header" href="#圆括号表达式分组表达式" id="圆括号表达式分组表达式">圆括号表达式(分组表达式)</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/grouped-expr.md">grouped-expr.md</a><br />
commit: 37ca438c9ac58448ecf304b735e71644e8127f3d <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>GroupedExpression</em> :<br />
   <code>(</code> <a href="expressions/../expressions.html"><em>Expression</em></a> <code>)</code></p>
</blockquote>
<p>由圆括号封闭的表达式的求值结果就是在其内的表达式的求值结果。
在表达式内部，圆括号可用于显式地指定表达式内部的求值顺序。</p>
<p>*圆括号表达式(parenthesized expression)<em>包装单个表达式，并对该表达式求值。
圆括号表达式的句法规则就是一对圆括号封闭一个被称为</em>封闭操作数(enclosed operand)*的表达式。</p>
<p>圆括号表达式被求值为其封闭操作数的值。
与其他表达式不同，圆括号表达式可以是<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式或值表达式</a>。
当封闭操作数是位置表达式时，它是一个位置表达式；当封闭操作数是一个值表达式是，它是一个值表达式。</p>
<p>圆括号可用于显式修改表达式中的子表达式的优先顺序。</p>
<p>圆括号表达式的一个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x: i32 = 2 + 3 * 4;
let y: i32 = (2 + 3) * 4;
assert_eq!(x, 14);
assert_eq!(y, 20);
<span class="boring">}
</span></code></pre></pre>
<p>当调用结构体的函数指针类型的成员时，必须使用括号，示例如下：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct A {
</span><span class="boring">   f: fn() -&gt; &amp;'static str
</span><span class="boring">}
</span><span class="boring">impl A {
</span><span class="boring">   fn f(&amp;self) -&gt; &amp;'static str {
</span><span class="boring">       &quot;The method f&quot;
</span><span class="boring">   }
</span><span class="boring">}
</span><span class="boring">let a = A{f: || &quot;The field f&quot;};
</span><span class="boring">
</span>assert_eq!( a.f (), &quot;The method f&quot;);
assert_eq!((a.f)(), &quot;The field f&quot;);
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#array-and-array-index-expressions" id="array-and-array-index-expressions">Array and array index expressions</a></h1>
<h1><a class="header" href="#数组和数组索引表达式" id="数组和数组索引表达式">数组和数组索引表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/array-expr.md">array-expr.md</a><br />
commit: 37ca438c9ac58448ecf304b735e71644e8127f3d <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<h2><a class="header" href="#array-expressions" id="array-expressions">Array expressions</a></h2>
<h2><a class="header" href="#数组表达式" id="数组表达式">数组表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ArrayExpression</em> :<br />
   <code>[</code> <em>ArrayElements</em><sup>?</sup> <code>]</code></p>
<p><em>ArrayElements</em> :<br />
      <a href="expressions/../expressions.html"><em>Expression</em></a> ( <code>,</code> <a href="expressions/../expressions.html"><em>Expression</em></a> )<sup>*</sup> <code>,</code><sup>?</sup><br />
   | <a href="expressions/../expressions.html"><em>Expression</em></a> <code>;</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>数组表达式</em>用来构建<a href="expressions/../types/array.html">数组</a>。
数组表达式有两种形式。</p>
<p>第一种形式是在数组中列举出所有的元素值。
这种形式的句法规则通过在方括号中放置统一类型的、逗号分隔的表达式来表现。
这样编写将生成一个包含这些表达式的值的数组，其中数组元素的顺序就是这些表达式写入的时顺序。</p>
<p>第二种形式的句法规则通过在方括号内放置两用个用分号(<code>;</code>)分隔的表达式来表现。
分号(<code>;</code>)前的表达式被称为<em>重复体操作数(repeat operand)</em>
分号(<code>;</code>)后的表达式被称为<em>数组长度操作数(length operand)</em>
其中，数组长度操作数必须是 <code>usize</code> 类型的，并且必须是<a href="expressions/../const_eval.html#constant-expressions">常量表达式</a>，比如是<a href="expressions/../tokens.html#literals">字面量</a>或<a href="expressions/../items/constant-items.html">常量项</a>。
也就是说，<code>[a; b]</code> 这种形式会创建包含 <code>b</code> 个 <code>a</code> 值的数组。
如果数组长度操作数的值大于 1，则要求 <code>a</code> 的类型实现了 <a href="expressions/../special-types-and-traits.html#copy"><code>Copy</code></a>，或 <code>a</code> 自己是一个常量项的<a href="expressions/path-expr.html">路径</a>。</p>
<p>当 <code>[a; b]</code> 形式的重复体操作数 <code>a</code> 是一个常量项时，其将被计算求值数组长度操作数 <code>b</code> 次。
如果数组长度操作数 <code>b</code> 为 0，则常量项根本不会被求值。
对于非常量项的表达式，只计算求值一次，然后将结果复制数组长度操作数 <code>b</code> 次。</p>
<div class="warning">
<p>警告：当数组长度操作数为 0 时，而重复体操作数是一个非常量项的情况下，目前在 <code>rustc</code> 中存在一个 bug，即值 <code>a</code> 会被求值，但不会被销毁而导致的内存泄漏。参见 <a href="https://github.com/rust-lang/rust/issues/74836">issue#74836</a>。</p>
</div>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>[1, 2, 3, 4];
[&quot;a&quot;, &quot;b&quot;, &quot;c&quot;, &quot;d&quot;];
[0; 128];              // 内含128个0的数组
[0u8, 0u8, 0u8, 0u8,];
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]; // 二维数组
const EMPTY: Vec&lt;i32&gt; = Vec::new();
[EMPTY; 2];
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#array-and-slice-indexing-expressions" id="array-and-slice-indexing-expressions">Array and slice indexing expressions</a></h2>
<h2><a class="header" href="#数组和切片索引表达式" id="数组和切片索引表达式">数组和切片索引表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>IndexExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>[</code> <a href="expressions/../expressions.html"><em>Expression</em></a> <code>]</code></p>
</blockquote>
<p><a href="expressions/../types/array.html">数组</a>和<a href="expressions/../types/slice.html">切片</a>类型的值(slice-typed values)可以通过后跟一个由方括号封闭一个类型为 <code>usize</code> 的表达式（索引）的方式来对此数组或切片进行索引检索。
如果数组是可变的，则其检索出的<a href="expressions/../expressions.html#place-expressions-and-value-expressions">内存位置</a>还可以被赋值。</p>
<p>对于数组和切片类型之外的索引表达式 <code>a[b]</code> 其实相当于执行 <code>*std::ops::Index::index(&amp;a, b)</code>，或者在可变位置表达式上下文中相当于执行 <code>*std::ops::IndexMut::index_mut(&amp;mut a, b)</code>。
与普通方法一样，Rust 也将在 <code>a</code> 上反复插入解引用操作，直到查找到对上述方法的实现。</p>
<p>数组和切片的索引是从零开始的。数组访问是一个<a href="expressions/../const_eval.html#constant-expressions">常量表达式</a>，因此数组索引的越界检查可以在编译时通过检查常量索引值本身进行。
否则，越界检查将在运行时执行，如果此时越界检查未通过，那将把当前线程置于 <em>panicked 状态</em>。</p>
<pre><pre class="playground"><code class="language-rust should_panic edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 默认情况下,`unconditional_panic` lint检查会执行 deny 级别的设置，
// 即 crate 在默认情况下会有外部属性设置 `#[deny(unconditional_panic)]`
// 而像 `([&quot;a&quot;, &quot;b&quot;])[n]` 这样的简单动态索引检索会被该 lint 检查出来，而提前报错，导致程序被拒绝编译。
// 因此这里调低 `unconditional_panic` 的 lint 级别以通过编译。
#![warn(unconditional_panic)]

([1, 2, 3, 4])[2];        // 3

let b = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
b[1][2];                  // 多维数组索引

let x = ([&quot;a&quot;, &quot;b&quot;])[10]; // 告警：索引越界

let n = 10; 
// 译者注：上行可以在 `#![warn(unconditional_panic)]` 被注释的情况下换成
// let n = if true {10} else {0};
// 试试，那下行就不会被 unconditional_panic lint 检查到了
  
let y = ([&quot;a&quot;, &quot;b&quot;])[n];  // panic

let arr = [&quot;a&quot;, &quot;b&quot;];
arr[10];                  // 告警：索引越界
<span class="boring">}
</span></code></pre></pre>
<p>数组和切片以外的类型可以通过实现 <a href="expressions/../../std/ops/trait.Index.html">Index</a> trait 和 <a href="expressions/../../std/ops/trait.IndexMut.html">IndexMut</a> trait 来达成数组索引表达式的效果。</p>
<h1><a class="header" href="#tuple-and-tuple-indexing-expressions" id="tuple-and-tuple-indexing-expressions">Tuple and tuple indexing expressions</a></h1>
<h1><a class="header" href="#元组和元组索引表达式" id="元组和元组索引表达式">元组和元组索引表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/tuple-expr.md">tuple-expr.md</a><br />
commit: 37ca438c9ac58448ecf304b735e71644e8127f3d <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<h2><a class="header" href="#tuple-expressions" id="tuple-expressions">Tuple expressions</a></h2>
<h2><a class="header" href="#元组表达式" id="元组表达式">元组表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TupleExpression</em> :<br />
   <code>(</code> <em>TupleElements</em><sup>?</sup> <code>)</code></p>
<p><em>TupleElements</em> :<br />
   ( <a href="expressions/../expressions.html"><em>Expression</em></a> <code>,</code> )<sup>+</sup> <a href="expressions/../expressions.html"><em>Expression</em></a><sup>?</sup></p>
</blockquote>
<p><em>元组表达式</em>用来构建<a href="expressions/../types/tuple.html">元组值</a>。</p>
<p>元组表达式的句法规则为：一对圆括号封闭的以逗号分隔的表达式列表，这些表达式被称为<em>元组初始化操作数(tuple initializer operands)</em>。
为了避免和<a href="expressions/grouped-expr.html">圆括号表达式</a>混淆，一元元组表达式的元组初始化操作数后的逗号不能省略。</p>
<p>元组表达式是一个<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>，它会被求值计算成一个元组类型的新值。
元组初始化操作数的数量构成元组的元数(arity)。
没有元组初始化操作数的元组表达式生成单元元组(unit tuple)。
对于其他元组表达式，第一个被写入的元组初始化操作数初始化第 0 个元素，随后的操作数依次初始化下一个开始的元素。
例如，在元组表达式 <code>('a', 'b', 'c')</code> 中，<code>'a'</code> 初始化第 0 个元素的值，<code>'b'</code> 初始化第 1 个元素，<code>'c'</code> 初始化第2个元素。</p>
<p>元组表达式和相应类型的示例：</p>
<table><thead><tr><th>表达式</th><th>类型</th></tr></thead><tbody>
<tr><td><code>()</code></td><td><code>()</code> (unit)</td></tr>
<tr><td><code>(0.0, 4.5)</code></td><td><code>(f64, f64)</code></td></tr>
<tr><td><code>(&quot;x&quot;.to_string(), )</code></td><td><code>(String, )</code></td></tr>
<tr><td><code>(&quot;a&quot;, 4usize, true)</code></td><td><code>(&amp;'static str, usize, bool)</code></td></tr>
</tbody></table>
<h2><a class="header" href="#tuple-indexing-expressions" id="tuple-indexing-expressions">Tuple indexing expressions</a></h2>
<h2><a class="header" href="#元组索引表达式" id="元组索引表达式">元组索引表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TupleIndexingExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>.</code> <a href="expressions/../tokens.html#tuple-index">TUPLE_INDEX</a></p>
</blockquote>
<p><em>元组索引表达式</em>被用来存取<a href="expressions/../types/tuple.html">元组</a>或[元组结构体][tuple structs]的字段。</p>
<p>元组索引表达式的句法规则为：一个被称为*元组操作数(tuple operand)*的表达式后跟一个 <code>.</code>，最后再后跟一个元组索引。
<em>元组索引</em>的句法规则要求该索引必须写成一个不能有前导零、下划线和后缀的<a href="expressions/../tokens.html#integer-literals">十进制字面量</a>的形式。
例如 <code>0</code> 和 <code>2</code> 是合法的元祖索引，但 <code>01</code>、<code>0_</code>、<code>0i32</code> 这些不行。</p>
<p>元组操作数的类型必须是<a href="expressions/../types/tuple.html">元组类型</a>或[元组结构体][tuple structs]。
元组索引必须是元组操作数类型的字段的名称。（译者注：这句感觉原文表达有问题，这里也给出原文 The tuple index must be a name of a field of the type of the tuple operand.）</p>
<p>对元组索引表达式的求值计算除了能求取其元组操作数的对应位置的值之外没有其他作用。
作为<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>，元组索引表达式的求值结果是元组操作数字段的位置，该字段与元组索引同名。</p>
<p>元组索引表达式示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 索引检索一个元组
let pair = (&quot;a string&quot;, 2);
assert_eq!(pair.1, 2);

// 索引检索一个元组结构体
<span class="boring">struct Point(f32, f32);
</span>let point = Point(1.0, 0.0);
assert_eq!(point.0, 1.0);
assert_eq!(point.1, 0.0);
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p><strong>注意</strong>：与字段访问表达式不同，元组索引表达式可以是<a href="expressions/./call-expr.html">调用表达式</a>的函数操作数。
（这之所以可行，）因为元组索引表达式不会与方法调用相混淆，因为方法名不可能是数字。</p>
</blockquote>
<blockquote>
<p><strong>注意</strong>：虽然数组和切片也有元素，但它们必须使用<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">数组或切片索引表达式</a>或<a href="expressions/../patterns.html#slice-patterns">切片模式</a>去访问它们的元素。</p>
</blockquote>
<h1><a class="header" href="#struct-expressions" id="struct-expressions">Struct expressions</a></h1>
<h1><a class="header" href="#结构体表达式" id="结构体表达式">结构体表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/struct-expr.md">struct-expr.md</a><br />
commit: 37ca438c9ac58448ecf304b735e71644e8127f3d <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>StructExpression</em> :<br />
      <em>StructExprStruct</em><br />
   | <em>StructExprTuple</em><br />
   | <em>StructExprUnit</em></p>
<p><em>StructExprStruct</em> :<br />
   <a href="expressions/../paths.html#paths-in-expressions"><em>PathInExpression</em></a> <code>{</code> (<em>StructExprFields</em> | <em>StructBase</em>)<sup>?</sup> <code>}</code></p>
<p><em>StructExprFields</em> :<br />
   <em>StructExprField</em> (<code>,</code> <em>StructExprField</em>)<sup>*</sup> (<code>,</code> <em>StructBase</em> | <code>,</code><sup>?</sup>)</p>
<p><em>StructExprField</em> :<br />
      <a href="expressions/../identifiers.html">IDENTIFIER</a><br />
   | (<a href="expressions/../identifiers.html">IDENTIFIER</a> | <a href="expressions/../tokens.html#tuple-index">TUPLE_INDEX</a>) <code>:</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
<p><em>StructBase</em> :<br />
   <code>..</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
<p><em>StructExprTuple</em> :<br />
   <a href="expressions/../paths.html#paths-in-expressions"><em>PathInExpression</em></a> <code>(</code><br />
      ( <a href="expressions/../expressions.html"><em>Expression</em></a> (<code>,</code> <a href="expressions/../expressions.html"><em>Expression</em></a>)<sup>*</sup> <code>,</code><sup>?</sup> )<sup>?</sup><br />
   <code>)</code></p>
<p><em>StructExprUnit</em> : <a href="expressions/../paths.html#paths-in-expressions"><em>PathInExpression</em></a></p>
</blockquote>
<p><em>结构体表达式</em>用来创建结构体、枚举或联合体的值。它由指向<a href="expressions/../items/structs.html">结构体</a>程序项、<a href="expressions/../items/enumerations.html">枚举变体</a>、<a href="expressions/../items/unions.html">联合体</a>程序项的路径，以及与此程序项的字段对应的值组成。
结构体表达式有三种形式：结构体(struct)、元组结构体(tuple)和单元结构体(unit)。</p>
<p>下面是结构体表达式的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Point { x: f64, y: f64 }
</span><span class="boring">struct NothingInMe { }
</span><span class="boring">struct TuplePoint(f64, f64);
</span><span class="boring">mod game { pub struct User&lt;'a&gt; { pub name: &amp;'a str, pub age: u32, pub score: usize } }
</span><span class="boring">struct Cookie; fn some_fn&lt;T&gt;(t: T) {}
</span>Point {x: 10.0, y: 20.0};
NothingInMe {};
TuplePoint(10.0, 20.0);
TuplePoint { 0: 10.0, 1: 20.0 }; // 效果和上一行一样
let u = game::User {name: &quot;Joe&quot;, age: 35, score: 100_000};
some_fn::&lt;Cookie&gt;(Cookie);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#field-struct-expression" id="field-struct-expression">Field struct expression</a></h2>
<h2><a class="header" href="#结构体表达式的字段设置" id="结构体表达式的字段设置">结构体表达式的字段设置</a></h2>
<p>用花括号把字段括起来的结构体表达式允许以任意顺序指定每个字段的值。字段名与值之间用冒号分隔。</p>
<p><a href="expressions/../items/unions.html">联合体</a>类型的值只能使用此句法创建，并且只能指定一个字段。</p>
<h2><a class="header" href="#functional-update-syntax" id="functional-update-syntax">Functional update syntax</a></h2>
<h2><a class="header" href="#函数式更新句法" id="函数式更新句法">函数式更新句法</a></h2>
<p>构造结构体类型的值的结构体表达式可以以 <code>..</code> 后跟一个表达式的句法结尾，这种句法表示这是一种函数式更新(functional update)。
<code>..</code> 后跟的表达式（此表达式被称为此函数式更新的基(base)）必须与正在构造的新结构体值是同一种结构体类型的。</p>
<p>整个结构体表达式先为已指定的字段使用已给定的值，然后再从基表达式(base expression)里为剩余未指定的字段移动或复制值。
与所有结构体表达式一样，此结构体类型的所有字段必须是<a href="expressions/../visibility-and-privacy.html">可见的</a>，甚至那些没有显式命名的字段也是如此。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Point3d { x: i32, y: i32, z: i32 }
</span>let mut base = Point3d {x: 1, y: 2, z: 3};
let y_ref = &amp;mut base.y;
Point3d {y: 0, z: 10, .. base}; // OK, 只有 base.x 获取进来了
drop(y_ref);
<span class="boring">}
</span></code></pre></pre>
<p>带花括号的结构体表达式不能直接用在<a href="expressions/loop-expr.html">循环</a>表达式或 <a href="expressions/if-expr.html#if-expressions">if</a>表达式的头部，也不能直接用在 <a href="expressions/if-expr.html#if-let-expressions">if let</a>或<a href="expressions/match-expr.html">匹配</a>表达式的<a href="expressions/../glossary.html#scrutinee">检验对象(scrutinee)</a>上。
但是，如果结构体表达式在另一个表达式内（例如在<a href="expressions/grouped-expr.html">圆括号</a>内），则可以用在这些情况下。</p>
<p>构造元组结构体时其字段名可以是代表索引的十进制整数数值。
这中表达方法还可以与基结构体一起使用来填充其余未指定的索引：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Color(u8, u8, u8);
let c1 = Color(0, 0, 0);  // 创建元组结构体的典型方法。
let c2 = Color{0: 255, 1: 127, 2: 0};  // 按索引来指定字段。
let c3 = Color{1: 0, ..c2};  // 使用基的字段值来填写结构体的所有其他字段。
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#struct-field-init-shorthand" id="struct-field-init-shorthand">Struct field init shorthand</a></h3>
<h3><a class="header" href="#初始化结构体字段的快捷方法" id="初始化结构体字段的快捷方法">初始化结构体字段的快捷方法</a></h3>
<p>当使用字段的名字（注意不是位置索引数字）初始化某数据结构（结构体、枚举、联合体）时，允许将 <code>fieldname: fieldname</code> 写成 <code>fieldname</code> 这样的简化形式。
这种句法让代码更少重复，更加紧凑。
例如：</p>
<p>For example:
For example:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Point3d { x: i32, y: i32, z: i32 }
</span><span class="boring">let x = 0;
</span><span class="boring">let y_value = 0;
</span><span class="boring">let z = 0;
</span>Point3d { x: x, y: y_value, z: z };
Point3d { x, y: y_value, z };
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#tuple-struct-expression" id="tuple-struct-expression">Tuple struct expression</a></h2>
<h2><a class="header" href="#元组结构体表达式" id="元组结构体表达式">元组结构体表达式</a></h2>
<p>用圆括号括起字段的结构体表达式构造出来的结构体为元组结构体。
虽然为了完整起见，也把它作为一个特定的（结构体）表达式列在这里，但实际上它等价于执行元组结构体构造器的<a href="expressions/call-expr.html">调用表达式</a>。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Position(i32, i32, i32);
Position(0, 0, 0);  // 创建元组结构体的典型方法。
let c = Position;  // `c` 是一个接收3个参数的函数。
let pos = c(8, 6, 7);  // 创建一个 `Position` 值。
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#unit-struct-expression" id="unit-struct-expression">Unit struct expression</a></h2>
<h2><a class="header" href="#单元结构体表达式" id="单元结构体表达式">单元结构体表达式</a></h2>
<p>单元结构体表达式只是单元结构体程序项(unit struct item)的路径。
也是指向此单元结构体的值的隐式常量。
单元结构体的值也可以用无字段结构体表达式来构造。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct Gamma;
let a = Gamma;  // Gamma的值。
let b = Gamma{};  // 和`a`的值完全一样。
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#call-expressions" id="call-expressions">Call expressions</a></h1>
<h1><a class="header" href="#调用表达式" id="调用表达式">调用表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/call-expr.md">call-expr.md</a><br />
commit: 31dc83fe187a87af2b162801d50f4bed171fecdb <br />
本章译文最后维护日期：2021-4-5</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>CallExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>(</code> <em>CallParams</em><sup>?</sup> <code>)</code></p>
<p><em>CallParams</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> ( <code>,</code> <a href="expressions/../expressions.html"><em>Expression</em></a> )<sup>*</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p><em>调用表达式</em>用来调用函数。
调用表达式的句法规则为：一个被称作*函数操作数(function operand)<em>的表达式，后跟一个圆括号封闭的逗号分割的被称为</em>参数操作数(argument operands)*的表达式列表。
如果函数最终返回，则此调用表达式执行完成。
对于<a href="expressions/../types/function-item.html">非函数类型</a>，表达式 <code>f(...)</code> 会使用 <a href="https://doc.rust-lang.org/std/ops/trait.Fn.html"><code>std::ops::Fn</code></a>、<a href="https://doc.rust-lang.org/std/ops/trait.FnMut.html"><code>std::ops::FnMut</code></a> 或 <a href="https://doc.rust-lang.org/std/ops/trait.FnOnce.html"><code>std::ops::FnOnce</code></a> 这些 trait 上的某一方法，选择使用哪个要看 <code>f</code> 如何获取其输入的参数，具体就是看是通过引用、可变引用、还是通过获取所有权来获取的。
如有需要，也可通过自动借用。
Rust 也会根据需要自动对 <code>f</code> 作解引用处理。</p>
<p>下面是一些调用表达式的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn add(x: i32, y: i32) -&gt; i32 { 0 }
</span>let three: i32 = add(1i32, 2i32);
let name: &amp;'static str = (|| &quot;Rust&quot;)();
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#disambiguating-function-calls" id="disambiguating-function-calls">Disambiguating Function Calls</a></h2>
<h2><a class="header" href="#函数调用的消歧" id="函数调用的消歧">函数调用的消歧</a></h2>
<p>为获得更直观的<a href="expressions/../paths.html#qualified-paths">完全限定的句法规则</a>，Rust 对所有函数调都作了糖化(sugar)处理。
根据当前作用域内的程序项调用的二义性，函数调用有可能需要完全限定。</p>
<blockquote>
<p><strong>注意</strong>：过去，Rust 社区在文档、议题、RFC 和其他社区文章中使用了术语“确定性函数调用句法(Unambiguous Function Call Syntax)”、“通用函数调用句法(Universal Function Call Syntax)” 或 “UFCS”。
但是，这个术语缺乏描述力，可能还会混淆当前的议题。
我们在这里提起这个词是为了便于搜索。</p>
</blockquote>
<p>少数几种情况下经常会出现一些导致方法调用或关联函数调用的接受者或引用对象不明确的情况。这些情况可包括：</p>
<ul>
<li>作用域内的多个 trait 为同一类型定义了相同名称的方法</li>
<li>自动解引(Auto-<code>deref</code>)用搞不定的情况；例如，区分智能指针本身的方法和指针所指对象上的方法</li>
<li>不带参数的方法，就像 <a href="https://doc.rust-lang.org/std/default/trait.Default.html#tymethod.default"><code>default()</code></a> 这样的和返回类型的属性(properties)的，如 <a href="https://doc.rust-lang.org/std/mem/fn.size_of.html"><code>size_of()</code></a></li>
</ul>
<p>为了解决这种二义性，程序员可以使用更具体的路径、类型或 trait 来明确指代他们想要的方法或函数。</p>
<p>例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">trait Pretty {
    fn print(&amp;self);
}

trait Ugly {
  fn print(&amp;self);
}

struct Foo;
impl Pretty for Foo {
    fn print(&amp;self) {}
}

struct Bar;
impl Pretty for Bar {
    fn print(&amp;self) {}
}
impl Ugly for Bar {
    fn print(&amp;self) {}
}

fn main() {
    let f = Foo;
    let b = Bar;

    // 我们可以这样做，因为对于`Foo`，我们只有一个名为 `print` 的程序项
    f.print();
    // 对于 `Foo`来说，这样是更明确了，但没必要
    Foo::print(&amp;f);
    // 如果你不喜欢简洁的话，那，也可以这样
    &lt;Foo as Pretty&gt;::print(&amp;f);

    // b.print(); // 错误： 发现多个 `print`
    // Bar::print(&amp;b); // 仍错： 发现多个 `print`

    // 必要，因为作用域内的多个程序项定义了 `print`
    &lt;Bar as Pretty&gt;::print(&amp;b);
}
</code></pre></pre>
<p>更多细节和动机说明请参考<a href="https://github.com/rust-lang/rfcs/blob/master/text/0132-ufcs.md">RFC 132</a>。</p>
<h1><a class="header" href="#method-call-expressions" id="method-call-expressions">Method-call expressions</a></h1>
<h1><a class="header" href="#方法调用表达式" id="方法调用表达式">方法调用表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/method-call-expr.md">method-call-expr.md</a><br />
commit: eb5290329316e96c48c032075f7dbfa56990702b <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MethodCallExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>.</code> <a href="expressions/../paths.html#paths-in-expressions"><em>PathExprSegment</em></a> <code>(</code><a href="expressions/call-expr.html"><em>CallParams</em></a><sup>?</sup> <code>)</code></p>
</blockquote>
<p><em>方法调用</em>由一个表达式（<em>接受者(receiver)</em>）后跟一个单点号(<code>.</code>)、一个表达式路径段(path segment)和一个圆括号封闭的的表达式列表组成。
方法调用被解析为特定 trait 上的关联<a href="expressions/../items/associated-items.html#methods">方法</a>时，如果点号左边的表达式有确切的已知的 <code>self</code>类型，则会静态地分发(statically dispatch)给在此类型下查找到的某个同名方法来执行；如果点号左边的表达式是间接的 <a href="expressions/../types/trait-object.html">trait对象</a>，则会采用动态分发(dynamically dispatch)的方式。</p>
<p><a href="expressions/../types/trait-object.html">trait object</a>.</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let pi: Result&lt;f32, _&gt; = &quot;3.14&quot;.parse();
let log_pi = pi.unwrap_or(1.0).log(2.72);
<span class="boring">assert!(1.14 &lt; log_pi &amp;&amp; log_pi &lt; 1.15)
</span><span class="boring">}
</span></code></pre></pre>
<p>在查找方法调用时，为了调用某个方法，可能会自动对接受者做解引用或借用。
这需要比其他函数更复杂的查找流程，因为这可能需要调用许多可能的方法。具体会用到下述步骤：</p>
<p>第一步是构建候选接受者类型的列表。通过重复对接受者表达式的类型作<a href="expressions/operator-expr.html#the-dereference-operator">解引用</a>，将遇到的每个类型添加到列表中，然后在最后再尝试进行一次<a href="expressions/../type-coercions.html#unsized-coercions">非固定尺寸类型自动强转(unsized coercion)</a>，如果成功，则将结果类型也添加到此类型列表里。
然后，再在这个列表中的每个候选类型 <code>T</code> 后紧跟着添加 <code>&amp;T</code> 和 <code>&amp;mut T</code> 候选项。</p>
<p>例如，接受者的类型为 <code>Box&lt;[i32;2]&gt;</code>，则候选类型为 <code>Box&lt;[i32;2]&gt;</code>，<code>&amp;Box&lt;[i32;2]&gt;</code>，<code>&amp;mut Box&lt;[i32;2]&gt;</code>，<code>[i32; 2]</code>（通过解引用得到），<code>&amp;[i32; 2]</code>，<code>&amp;mut [i32; 2]</code>，<code>[i32]</code>（通过非固定尺寸类型自动强转得到），<code>&amp;[i32]</code>，最后是 <code>&amp;mut [i32]</code>。</p>
<p>然后，对每个候选类型 <code>T</code>，编译器会它的以下位置上搜索一个<a href="expressions/../visibility-and-privacy.html">可见的</a>同名方法，找到后还会把此方法所属的类型当做接受者：</p>
<ol>
<li><code>T</code> 的固有方法（直接在 <code>T</code> 上实现的方法）。</li>
<li>由 <code>T</code> 已实现的<a href="expressions/../visibility-and-privacy.html">可见的</a> trait 所提供的任何方法。如果 <code>T</code> 是一个类型参数，则首先查找由 <code>T</code> 上的 trait约束所提供的方法。然后查找作用域内所有其他的方法。</li>
</ol>
<blockquote>
<p>注意：查找是按顺序进行的，这有时会导致出现不太符合直觉的结果。
下面的代码将打印 “In trait impl!”，因为首先会查找 <code>&amp;self</code> 上的方法，在找到结构体 <code>Foo</code> 的（接受者类型为）<code>&amp;mut self</code> 的（固有）方法（<code>Foo::bar</code>）之前先找到（接受者类型为 <code>&amp;self</code> 的）trait方法（<code>Bar::bar</code>）。</p>
<pre><pre class="playground"><code class="language-rust edition2018">struct Foo {}

trait Bar {
  fn bar(&amp;self);
}

impl Foo {
  fn bar(&amp;mut self) {
    println!(&quot;In struct impl!&quot;)
  }
}

impl Bar for Foo {
  fn bar(&amp;self) {
    println!(&quot;In trait impl!&quot;)
  }
}

fn main() {
  let mut f = Foo{};
  f.bar();
}
</code></pre></pre>
</blockquote>
<p>如果上面这第二步查找导致了多个可能的候选类型<sup class="footnote-reference"><a href="#译者注">1</a></sup>，就会导致报错，此时必须将接受者<a href="expressions/call-expr.html#disambiguating-function-calls">转换</a>为适当的接受者类型再来进行方法调用。</p>
<p>此方法过程不考虑接受者的可变性或生存期，也不考虑方法是否为非安全(<code>unsafe</code>)方法。
一旦查找到了一个方法，如果由于这些（可变性、生存期或健全性）原因中的一个（或多个）而不能调用，则会报编译错误。</p>
<p>如果某步碰到了存在多个可能性方法的情况，比如泛型方法之间或 trait方法之间被认为是相同的，那么它就会导致编译错误。
这些情况就需要使用<a href="expressions/call-expr.html#disambiguating-function-calls">函数调用的消歧句法</a>来为方法调用或函数调用消除歧义。</p>
<div class="warning">
<p><em><strong>警告：</strong></em> 对于 <a href="expressions/../types/trait-object.html">trait对象</a>，如果有一个与 trait方法同名的固有方法，那么当尝试在方法调用表达式(method call expression)中调用该方法时，将编译报错。
此时，可以使用<a href="expressions/call-expr.html#disambiguating-function-calls">消除函数调用歧义的句法</a>来明确调用语义。
在 trait对象上使用消除函数调用歧义的句法，将只能调用 trait方法，无法调用固有方法。
所以只要不在 trait对象上定义和 trait方法同名的固有方法就不会碰到这种麻烦。</p>
</div>
<p><sup class="footnote-reference"><a href="#译者注">1</a></sup>：这个应该跟后面说的方法名歧义了一样，如果类型 <code>T</code> 的两个 trait 都有调用的那个方法，那此方法的调用者类型就不能确定了，就需要消歧。</p>
<!-- 上面这几个链接从原文来替换时需小心 -->
<h1><a class="header" href="#field-access-expressions" id="field-access-expressions">Field access expressions</a></h1>
<h1><a class="header" href="#字段访问表达式" id="字段访问表达式">字段访问表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/field-expr.md">field-expr.md</a><br />
commit: 23672971a16c69ea894bef24992b74912cfe5d25 <br />
本章译文最后维护日期：2021-4-5</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>FieldExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>.</code> <a href="expressions/../identifiers.html">IDENTIFIER</a></p>
</blockquote>
<p>*字段表达式(field expression)*是计算求取<a href="expressions/../items/structs.html">结构体</a>或<a href="expressions/../items/unions.html">联合体</a>的字段的内存位置的<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>。
当操作数<a href="expressions/../expressions.html#mutability">可变</a>时，其字段表达式也是可变的。</p>
<p>*字段表达式(field expression)<em>的句法规则为：一个被称为</em>容器操作数(container operand)*的表达式后跟一个单点号(<code>.</code>)，最后是一个<a href="expressions/../identifiers.html">标识符</a>。
字段表达式后面不能再紧跟着一个被圆括号封闭起来的逗号分割的表达式列表（这种表示这是一个<a href="expressions/method-call-expr.html">方法调用表达式</a>）。
因此字段表达式不能是调用表达式的函数调用者。</p>
<p>字段表达式代表<a href="expressions/../items/structs.html">结构体(<code>struct</code>)</a>或<a href="expressions/../items/unions.html">联合体(<code>union</code>)</a>的字段。要调用存储在结构体的字段中的函数，需要在此字段表达式外加上圆括号。</p>
<blockquote>
<p><strong>注意</strong>：如果要在调用表达式中使用它(来调用函数)，要把此字段表达式先用圆括号包装成一个<a href="expressions/grouped-expr.html">圆括号表达式</a>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct HoldsCallable&lt;F: Fn()&gt; { callable: F }
</span>let holds_callable = HoldsCallable { callable: || () };

// 非法: 会被解析为调用 &quot;callable&quot;方法
// holds_callable.callable();

// 合法
(holds_callable.callable)();
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<p>示例：</p>
<!-- ignore: needs lots of support code -->
<pre><code class="language-rust ignore">mystruct.myfield;
foo().x;
(Struct {a: 10, b: 20}).a;
(mystruct.function_field)() // 调用表达式里包含一个字段表达式
</code></pre>
<h2><a class="header" href="#automatic-dereferencing" id="automatic-dereferencing">Automatic dereferencing</a></h2>
<h2><a class="header" href="#自动解引用" id="自动解引用">自动解引用</a></h2>
<p>如果容器操作数的类型实现了 <a href="expressions/../special-types-and-traits.html#deref-and-derefmut"><code>Deref</code></a> 或 <a href="expressions/../special-types-and-traits.html#deref-and-derefmut"><code>DerefMut</code></a>（这取决于该操作数是否为<a href="expressions/../expressions.html#mutability">可变</a>），则会尽可能多次地<em>自动解引用(automatically dereferenced)</em>，以使字段访问成为可能。
这个过程也被简称为<em>自动解引用(autoderef)</em>。</p>
<h2><a class="header" href="#borrowing" id="borrowing">Borrowing</a></h2>
<h2><a class="header" href="#借用" id="借用">借用</a></h2>
<p>当借用时，结构体的各个字段以及对结构体的整体引用都被视为彼此分离的实体。
如果结构体没有实现 <a href="expressions/../special-types-and-traits.html#drop"><code>Drop</code></a>，同时该结构体又存储在局部变量中，（这种各个字段被视为彼此分离的单独实体的逻辑）还适用于每个字段的移出(move out)。
但如果对 <a href="expressions/../special-types-and-traits.html#boxt"><code>Box</code></a>化之外的用户自定义类型执行自动解引用，这（种各个字段被视为彼此分离的单独实体的逻辑）就不适用了。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct A { f1: String, f2: String, f3: String }
let mut x: A;
<span class="boring">x = A {
</span><span class="boring">    f1: &quot;f1&quot;.to_string(),
</span><span class="boring">    f2: &quot;f2&quot;.to_string(),
</span><span class="boring">    f3: &quot;f3&quot;.to_string()
</span><span class="boring">};
</span>let a: &amp;mut String = &amp;mut x.f1; // x.f1 被可变借用
let b: &amp;String = &amp;x.f2;         // x.f2 被不可变借用
let c: &amp;String = &amp;x.f2;         // 可以被再次借用
let d: String = x.f3;           // 从 x.f3 中移出
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#closure-expressions" id="closure-expressions">Closure expressions</a></h1>
<h1><a class="header" href="#闭包表达式" id="闭包表达式">闭包表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/closure-expr.md">closure-expr.md</a><br />
commit: d23f9da8469617e6c81121d9fd123443df70595d <br />
本章译文最后维护日期：2021-5-6</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ClosureExpression</em> :<br />
   <code>move</code><sup>?</sup><br />
   ( <code>||</code> | <code>|</code> <em>ClosureParameters</em><sup>?</sup> <code>|</code> )<br />
   (<a href="expressions/../expressions.html"><em>Expression</em></a> | <code>-&gt;</code> <a href="expressions/../types.html#type-expressions"><em>TypeNoBounds</em></a> <a href="expressions/block-expr.html"><em>BlockExpression</em></a>)</p>
<p><em>ClosureParameters</em> :<br />
   <em>ClosureParam</em> (<code>,</code> <em>ClosureParam</em>)<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>ClosureParam</em> :<br />
   <a href="expressions/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> <a href="expressions/../patterns.html"><em>PatternNoTopAlt</em></a> ( <code>:</code> <a href="expressions/../types.html#type-expressions"><em>Type</em></a> )<sup>?</sup></p>
</blockquote>
<p><em>闭包表达式</em>，也被称为 lambda表达式或 lambda，它定义了一个<a href="expressions/../types/closure.html">闭包类型</a>，并把此表达式求值计算为该类型的值。
闭包表达式的句法规则为：先是一个可选的 <code>move</code>关键字，后跟一对管道定界符(<code>|</code>)封闭的逗号分割的被称为<em>闭包参数(closure parameters)<em>的<a href="expressions/../patterns.html">模式</a>列表（每个闭包参数都可选地通过 <code>:</code> 后跟其类型），再可选地通过 <code>-&gt;</code> 后跟一个</em>返回类型</em>，最后是被称为<em>闭包体操作数(closure body operand)</em> 的表达式。
代表闭包参数的每个模式后面的可选类型是该模式的类型标注(type annotations)。
如果存在返回类型，则闭包体表达式必须是一个普通的<a href="expressions/block-expr.html">块</a>(表达式)。</p>
<p>闭包表达式本质是将一组参数映射到参数后面的表达式的函数。
与 <a href="expressions/../statements.html#let-statements"><code>let</code>绑定</a>一样，闭包参数也是不可反驳型<a href="expressions/../patterns.html">模式</a>的，其类型标注是可选的，如果没有给出，则从上下文推断。
每个闭包表达式都有一个唯一的匿名类型。</p>
<p>特别值得注意的是闭包表达式能<em>捕获它们被定义时的环境中的变量(capture their environment)</em>，而普通的<a href="expressions/../items/functions.html">函数定义</a>则不能。
如果没有关键字 <code>move</code>，闭包表达式将[推断它该如何从其环境中捕获每个变量][infers how it captures each variable from its environment]，它倾向于通过共享引用来捕获，从而有效地借用闭包体中用到的所有外部变量。
如果有必要，编译器会推断出应该采用可变引用，还是应该从环境中移动或复制值（取决于这些变量的类型）。
闭包可以通过前缀关键字 <code>move</code> 来强制通过复制值或移动值的方式捕获其环境变量。
这通常是为了确保当前闭包的生存期类型为 <code>'static</code>。</p>
<p>编译器将通过闭包对其捕获的变量的处置方式来确定此闭包类型将实现的[闭包trait][closure traits]。
如果所有捕获的类型都实现了 <a href="expressions/../special-types-and-traits.html#send"><code>Send</code></a> 和/或 <a href="expressions/../special-types-and-traits.html#sync"><code>Sync</code></a>，那么此闭包类型也实现了 <code>Send</code> 和/或 <code>Sync</code>。
这些存在这些 trait，函数可以通过泛型的方式接受各种闭包，即便闭包的类型名无法被确切指定。</p>
<h2><a class="header" href="#closure-trait-implementations" id="closure-trait-implementations">Closure trait implementations</a></h2>
<h2><a class="header" href="#闭包trait-的实现" id="闭包trait-的实现">闭包trait 的实现</a></h2>
<p>当前闭包类型实现哪一个闭包trait 依赖于该闭包如何捕获变量和这些变量的类型。
了解闭包如何和何时实现 <code>Fn</code>、<code>FnMut</code> 和 <code>FnOnce</code> 这三类 trait，请参看<a href="expressions/../types/closure.html#call-traits-and-coercions">调用trait 和自动强转</a>那一章。
如果所有捕获的类型都实现了 <a href="expressions/../special-types-and-traits.html#send"><code>Send</code></a> 和/或 <a href="expressions/../special-types-and-traits.html#sync"><code>Sync</code></a>，那么此闭包类型也实现了 <code>Send</code> 和/或 <code>Sync</code>。</p>
<h2><a class="header" href="#example" id="example">Example</a></h2>
<h2><a class="header" href="#示例-3" id="示例-3">示例</a></h2>
<p>在下面例子中，我们定义了一个名为 <code>ten_times</code> 的函数，它接受高阶函数参数，然后我们传给它一个闭包表达式作为实参并调用它。
之后又定义了一个使用移动语义从环境中捕获变量的闭包表达式来供该函数调用。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn ten_times&lt;F&gt;(f: F) where F: Fn(i32) {
    for index in 0..10 {
        f(index);
    }
}

ten_times(|j| println!(&quot;hello, {}&quot;, j));
// 带类型标注 i32
ten_times(|j: i32| -&gt; () { println!(&quot;hello, {}&quot;, j) });

let word = &quot;konnichiwa&quot;.to_owned();
ten_times(move |j| println!(&quot;{}, {}&quot;, word, j));
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes-on-closure-parameters" id="attributes-on-closure-parameters">Attributes on closure parameters</a></h2>
<h2><a class="header" href="#闭包参数上的属性" id="闭包参数上的属性">闭包参数上的属性</a></h2>
<p>闭包参数上的属性遵循与<a href="expressions/../items/functions.html#attributes-on-function-parameters">常规函数参数</a>上相同的规则和限制。</p>
<h1><a class="header" href="#loops" id="loops">Loops</a></h1>
<h1><a class="header" href="#循环" id="循环">循环</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/loop-expr.md">loop-expr.md</a><br />
commit: ac4ff0f3d5f980798b2463777d07e6060554c8c3 <br />
本章译文最后维护日期：2021-6-27</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LoopExpression</em> :<br />
   <a href="expressions/loop-expr.html#loop-labels"><em>LoopLabel</em></a><sup>?</sup> (<br />
         <a href="expressions/loop-expr.html#infinite-loops"><em>InfiniteLoopExpression</em></a><br />
      | <a href="expressions/loop-expr.html#predicate-loops"><em>PredicateLoopExpression</em></a><br />
      | <a href="expressions/loop-expr.html#predicate-pattern-loops"><em>PredicatePatternLoopExpression</em></a><br />
      | <a href="expressions/loop-expr.html#iterator-loops"><em>IteratorLoopExpression</em></a><br />
   )</p>
</blockquote>
<p>Rust支持四种循环表达式：</p>
<ul>
<li><a href="expressions/loop-expr.html#infinite-loops"><code>loop</code>表达式</a>表示一个无限循环。</li>
<li><a href="expressions/loop-expr.html#predicate-loops"><code>while</code>表达式</a>不断循环，直到谓词为假。</li>
<li><a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code>表达式</a>循环测试给定模式。</li>
<li><a href="expressions/loop-expr.html#iterator-loops"><code>for</code>表达式</a>从迭代器中循环取值，直到迭代器为空。</li>
</ul>
<p>所有四种类型的循环都支持 <a href="expressions/loop-expr.html#break-expressions"><code>break</code>表达式</a>、<a href="expressions/loop-expr.html#continue-expressions"><code>continue</code>表达式</a>和<a href="expressions/loop-expr.html#loop-labels">循环标签(label)</a>。
只有 <code>loop</code>循环支持对循环体<a href="expressions/loop-expr.html#break-and-loop-values">非平凡求值(evaluation to non-trivial values)</a><sup class="footnote-reference"><a href="#译注1">1</a></sup>。</p>
<h2><a class="header" href="#infinite-loops" id="infinite-loops">Infinite loops</a></h2>
<h2><a class="header" href="#无限循环" id="无限循环">无限循环</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>InfiniteLoopExpression</em> :<br />
   <code>loop</code> <a href="expressions/block-expr.html"><em>BlockExpression</em></a></p>
</blockquote>
<p><code>loop</code>表达式会不断地重复地执行它代码体内的代码：<code>loop { println!(&quot;I live.&quot;); }</code>。</p>
<p>没有包含关联的 <code>break</code>表达式的 <code>loop</code>表达式是发散的，并且具有类型 <a href="expressions/../types/never.html"><code>!</code></a>。
包含相应 <code>break</code>表达式的 <code>loop</code>表达式可以结束循环，并且此表达式的类型必须与 <code>break</code>表达式的类型兼容。</p>
<h2><a class="header" href="#predicate-loops" id="predicate-loops">Predicate loops</a></h2>
<h2><a class="header" href="#谓词循环" id="谓词循环">谓词循环</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>PredicateLoopExpression</em> :<br />
   <code>while</code> <a href="expressions/../expressions.html"><em>Expression</em></a><sub><em>排除结构体表达式</em></sub> <a href="expressions/block-expr.html"><em>BlockExpression</em></a></p>
</blockquote>
<p><code>while</code>循环从对<a href="expressions/../types/boolean.html">布尔型</a>的循环条件操作数求值开始。
如果循环条件操作数的求值结果为 <code>true</code>，则执行循环体块，然后控制流返回到循环条件操作数。如果循环条件操作数的求值结果为 <code>false</code>，则 <code>while</code>表达式完成。</p>
<p>举个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut i = 0;

while i &lt; 10 {
    println!(&quot;hello&quot;);
    i = i + 1;
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#predicate-pattern-loops" id="predicate-pattern-loops">Predicate pattern loops</a></h2>
<h2><a class="header" href="#谓词模式循环" id="谓词模式循环">谓词模式循环</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<a href="expressions/loop-expr.html#predicate-pattern-loops"><em>PredicatePatternLoopExpression</em></a> :<br />
   <code>while</code> <code>let</code> <a href="expressions/../patterns.html"><em>Pattern</em></a> <code>=</code> <a href="expressions/match-expr.html"><em>Scrutinee</em></a><sub><em>排除惰性布尔运算符表达式</em></sub>
<a href="expressions/block-expr.html"><em>BlockExpression</em></a></p>
</blockquote>
<p><code>while let</code>循环在语义上类似于 <code>while</code>循环，但它用 <code>let</code>关键字后紧跟着一个模式、一个 <code>=</code>、一个<a href="expressions/../glossary.html#scrutinee">检验对象(scrutinee)</a>表达式和一个块表达式，来替代原来的条件表达式。
如果检验对象表达式的值与模式匹配，则执行循环体块，然后控制流再返回到模式匹配语句。如果不匹配，则 <code>while</code>表达式执行完成。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut x = vec![1, 2, 3];

while let Some(y) = x.pop() {
    println!(&quot;y = {}&quot;, y);
}

while let _ = 5 {
    println!(&quot;不可反驳模式总是会匹配成功&quot;);
    break;
}
<span class="boring">}
</span></code></pre></pre>
<p><code>while let</code>循环等价于包含匹配(<code>match</code>)表达式的 <code>loop</code>表达式。
如下：</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">'label: while let PATS = EXPR {
    /* loop body */
}
</code></pre>
<p>等价于</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">'label: loop {
    match EXPR {
        PATS =&gt; { /* loop body */ },
        _ =&gt; break,
    }
}
</code></pre>
<p>可以使用操作符 <code>|</code> 指定多个模式。
这与匹配(<code>match</code>)表达式中的 <code>|</code> 具有相同的语义：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut vals = vec![2, 3, 1, 2, 2];
while let Some(v @ 1) | Some(v @ 2) = vals.pop() {
    // 打印 2, 2, 然后 1
    println!(&quot;{}&quot;, v);
}
<span class="boring">}
</span></code></pre></pre>
<p>与 <a href="expressions/if-expr.html#if-let-expressions"><code>if let</code>表达式</a>的情况一样，检验表达式不能是一个<a href="expressions/operator-expr.html#lazy-boolean-operators">懒惰布尔运算符表达式</a>。</p>
<h2><a class="header" href="#iterator-loops" id="iterator-loops">Iterator loops</a></h2>
<h2><a class="header" href="#迭代器循环" id="迭代器循环">迭代器循环</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>IteratorLoopExpression</em> :<br />
   <code>for</code> <a href="expressions/../patterns.html"><em>Pattern</em></a> <code>in</code> <a href="expressions/../expressions.html"><em>Expression</em></a><sub><em>排除结构体表达式</em></sub>
<a href="expressions/block-expr.html"><em>BlockExpression</em></a></p>
</blockquote>
<p><code>for</code>表达式是一个用于在 <code>std::iter::IntoIterator</code> 的某个迭代器实现提供的元素上进行循环的语法结构。
如果迭代器生成一个值，该值将与此 <code>for</code>表达式提供的不可反驳型模式进行匹配，执行循环体，然后控制流返回到 <code>for</code>循环的头部。
如果迭代器为空了，则 <code>for</code>表达式执行完成。</p>
<p><code>for</code>循环遍历数组内容的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let v = &amp;[&quot;apples&quot;, &quot;cake&quot;, &quot;coffee&quot;];

for text in v {
    println!(&quot;I like {}.&quot;, text);
}
<span class="boring">}
</span></code></pre></pre>
<p><code>for</code>循环遍历一个整数序列的例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut sum = 0;
for n in 1..11 {
    sum += n;
}
assert_eq!(sum, 55);
<span class="boring">}
</span></code></pre></pre>
<p><code>for</code>循环等价于后面的块表达式。</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">'label: for PATTERN in iter_expr {
    /* loop body */
}
</code></pre>
<p>等价于：</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">{
    let result = match IntoIterator::into_iter(iter_expr) {
        mut iter =&gt; 'label: loop {
            let mut next;
            match Iterator::next(&amp;mut iter) {
                Option::Some(val) =&gt; next = val,
                Option::None =&gt; break,
            };
            let PATTERN = next;
            let () = { /* loop body */ };
        },
    };
    result
}
</code></pre>
<p>这里的 <code>IntoIterator</code>、<code>Iterator</code> 和 <code>Option</code> 是标准库的程序项(standard library item)，不是当前作用域中解析的的任何名称。
变量名 <code>next</code>、<code>iter</code> 和 <code>val</code> 也仅用于表述需要，实际上它们不是用户可以输入的名称。</p>
<blockquote>
<p><strong>注意</strong>：上面代码里使用外层 <code>matche</code> 来确保 <code>iter_expr</code> 中的任何<a href="expressions/../expressions.html#temporaries">临时值</a>在循环结束前不会被销毁。
<code>next</code> 先声明后赋值是因为这样能让编译器更准确地推断出类型。</p>
</blockquote>
<h2><a class="header" href="#loop-labels" id="loop-labels">Loop labels</a></h2>
<h2><a class="header" href="#循环标签" id="循环标签">循环标签</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LoopLabel</em> :<br />
   <a href="expressions/../tokens.html#lifetimes-and-loop-labels">LIFETIME_OR_LABEL</a> <code>:</code></p>
</blockquote>
<p>一个循环表达式可以选择设置一个<em>标签</em>。
这类标签被标记为循环表达式之前的生存期（标签），如 <code>'foo: loop { break 'foo; }</code>、<code>'bar: while false {}</code>、<code>'humbug: for _ in 0..0 {}</code>。
如果循环存在标签，则嵌套在该循环中的带此标签的 <code>break</code>表达式和 <code>continue</code>表达式可以退出此标签标记的循环层或将控制流返回至此标签标记的循环层的头部。
具体请参见后面的 <a href="expressions/loop-expr.html#break-expressions">break表达式</a>和 <a href="expressions/loop-expr.html#continue-expressions">continue表达式</a>。</p>
<h2><a class="header" href="#break-expressions" id="break-expressions"><code>break</code> expressions</a></h2>
<h2><a class="header" href="#break表达式" id="break表达式"><code>break</code>表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>BreakExpression</em> :<br />
   <code>break</code> <a href="expressions/../tokens.html#lifetimes-and-loop-labels">LIFETIME_OR_LABEL</a><sup>?</sup> <a href="expressions/../expressions.html"><em>Expression</em></a><sup>?</sup></p>
</blockquote>
<p>当遇到 <code>break</code> 时，相关的循环体的执行将立即结束，例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut last = 0;
for x in 1..100 {
    if x &gt; 12 {
        break;
    }
    last = x;
}
assert_eq!(last, 12);
<span class="boring">}
</span></code></pre></pre>
<p><code>break</code>表达式通常与包含 <code>break</code>表达式的最内层 <code>loop</code>、<code>for</code>或 <code>while</code>循环相关联，但是可以使用<a href="expressions/loop-expr.html#loop-labels">循环标签</a>来指定受影响的循环层（此循环层必须是封闭该 break表达式的循环之一）。
例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>'outer: loop {
    while true {
        break 'outer;
    }
}
<span class="boring">}
</span></code></pre></pre>
<p><code>break</code>表达式只允许在循环体内使用，它有 <code>break</code>、<code>break 'label</code> 或（<a href="expressions/loop-expr.html#break-and-loop-values">参见后面</a>）<code>break EXPR</code> 或 <code>break 'label EXPR</code> 这四种形式。</p>
<h2><a class="header" href="#continue-expressions" id="continue-expressions"><code>continue</code> expressions</a></h2>
<h2><a class="header" href="#continue表达式" id="continue表达式"><code>continue</code>表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ContinueExpression</em> :<br />
   <code>continue</code> <a href="expressions/../tokens.html#lifetimes-and-loop-labels">LIFETIME_OR_LABEL</a><sup>?</sup></p>
</blockquote>
<p>当遇到 <code>continue</code> 时，相关的循环体的当前迭代将立即结束，并将控制流返回到循环头。
在 <code>while</code>循环的情况下，循环头是控制循环的条件表达式。
在 <code>for</code>循环的情况下，循环头是控制循环的调用表达式。</p>
<p>与 <code>break</code> 一样，<code>continue</code> 通常与最内层的循环相关联，但可以使用 <code>continue 'label</code> 来指定受影响的循环层。
<code>continue</code>表达式只允许在循环体内部使用。</p>
<h2><a class="header" href="#break-and-loop-values" id="break-and-loop-values"><code>break</code> and loop values</a></h2>
<h2><a class="header" href="#break和loop返回值" id="break和loop返回值"><code>break</code>和<code>loop</code>返回值</a></h2>
<p>当使用 <code>loop</code>循环时，可以使用 <code>break</code>表达式从循环中返回一个值，通过形如 <code>break EXPR</code> 或 <code>break 'label EXPR</code> 来返回，其中 <code>EXPR</code> 是一个表达式，它的结果被从 <code>loop</code>循环中返回。
例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let (mut a, mut b) = (1, 1);
let result = loop {
    if b &gt; 10 {
        break b;
    }
    let c = a + b;
    a = b;
    b = c;
};
// 斐波那契数列中第一个大于10的值：
assert_eq!(result, 13);
<span class="boring">}
</span></code></pre></pre>
<p>如果 <code>loop</code> 有关联的 <code>break</code>，则不认为该循环是发散的，并且 <code>loop</code>表达式的类型必须与每个 <code>break</code>表达式的类型兼容。
其后不跟表达式的 <code>break</code> 被认为与后跟 <code>()</code> 的<code>break</code>表达式的效果相同。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>求得 <code>()</code> 类型以外的值。</p>
</div>
<!-- 上面这几个链接从原文来替换时需小心 -->
<h1><a class="header" href="#range-expressions" id="range-expressions">Range expressions</a></h1>
<h1><a class="header" href="#区间表达式" id="区间表达式">区间表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/range-expr.md">range-expr.md</a><br />
commit: eb5290329316e96c48c032075f7dbfa56990702b <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>RangeExpression</em> :<br />
      <em>RangeExpr</em><br />
   | <em>RangeFromExpr</em><br />
   | <em>RangeToExpr</em><br />
   | <em>RangeFullExpr</em><br />
   | <em>RangeInclusiveExpr</em><br />
   | <em>RangeToInclusiveExpr</em></p>
<p><em>RangeExpr</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>..</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
<p><em>RangeFromExpr</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>..</code></p>
<p><em>RangeToExpr</em> :<br />
   <code>..</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
<p><em>RangeFullExpr</em> :<br />
   <code>..</code></p>
<p><em>RangeInclusiveExpr</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>..=</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
<p><em>RangeToInclusiveExpr</em> :<br />
   <code>..=</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><code>..</code> 和 <code>..=</code> 操作符会根据下表中的规则构造 <code>std::ops::Range</code>（或 <code>core::ops::Range</code>）的某一变体类型的对象：</p>
<table><thead><tr><th>产生式/句法规则</th><th>句法</th><th>类型</th><th>区间语义</th></tr></thead><tbody>
<tr><td><em>RangeExpr</em></td><td>start<code>..</code>end</td><td><a href="https://doc.rust-lang.org/std/ops/struct.Range.html">std::ops::Range</a></td><td>start ≤ x &lt; end</td></tr>
<tr><td><em>RangeFromExpr</em></td><td>start<code>..</code></td><td><a href="https://doc.rust-lang.org/std/ops/struct.RangeFrom.html">std::ops::RangeFrom</a></td><td>start ≤ x</td></tr>
<tr><td><em>RangeToExpr</em></td><td><code>..</code>end</td><td><a href="https://doc.rust-lang.org/std/ops/struct.RangeTo.html">std::ops::RangeTo</a></td><td>x &lt; end</td></tr>
<tr><td><em>RangeFullExpr</em></td><td><code>..</code></td><td><a href="https://doc.rust-lang.org/std/ops/struct.RangeFull.html">std::ops::RangeFull</a></td><td>-</td></tr>
<tr><td><em>RangeInclusiveExpr</em></td><td>start<code>..=</code>end</td><td><a href="https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html">std::ops::RangeInclusive</a></td><td>start ≤ x ≤ end</td></tr>
<tr><td><em>RangeToInclusiveExpr</em></td><td><code>..=</code>end</td><td><a href="https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html">std::ops::RangeToInclusive</a></td><td>x ≤ end</td></tr>
</tbody></table>
<p>举例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>1..2;   // std::ops::Range
3..;    // std::ops::RangeFrom
..4;    // std::ops::RangeTo
..;     // std::ops::RangeFull
5..=6;  // std::ops::RangeInclusive
..=7;   // std::ops::RangeToInclusive
<span class="boring">}
</span></code></pre></pre>
<p>下面的表达式是等价的。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = std::ops::Range {start: 0, end: 10};
let y = 0..10;

assert_eq!(x, y);
<span class="boring">}
</span></code></pre></pre>
<p>区间能在 <code>for</code>循环里使用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for i in 1..11 {
    println!(&quot;{}&quot;, i);
}
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#if-and-if-let-expressions" id="if-and-if-let-expressions"><code>if</code> and <code>if let</code> expressions</a></h1>
<h1><a class="header" href="#if和-if-let表达式" id="if和-if-let表达式"><code>if</code>和 <code>if let</code>表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/if-expr.md">if-expr.md</a><br />
commit: ac4ff0f3d5f980798b2463777d07e6060554c8c3 <br />
本章译文最后维护日期：2021-06-27</p>
</blockquote>
<h2><a class="header" href="#if-expressions" id="if-expressions"><code>if</code> expressions</a></h2>
<h2><a class="header" href="#if表达式" id="if表达式"><code>if</code>表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>IfExpression</em> :<br />
   <code>if</code> <a href="expressions/../expressions.html"><em>Expression</em></a><sub><em>排除结构体表达式</em></sub> <a href="expressions/block-expr.html"><em>BlockExpression</em></a><br />
   (<code>else</code> (
<a href="expressions/block-expr.html"><em>BlockExpression</em></a>
| <em>IfExpression</em>
| <em>IfLetExpression</em> ) )<sup>?</sup></p>
</blockquote>
<p><code>if</code>表达式是程序控制中的一个条件分支。<code>if</code>表达式的句法是一个条件操作数（operand）后紧跟一个块，再后面是任意数量的 <code>else if</code>条件表达式和块，最后是一个可选的尾部 <code>else</code>块。
条件操作数的类型必须是<a href="expressions/../types/boolean.html">布尔型</a>。如果条件操作数的求值结果为 <code>true</code>，则执行紧跟的块，并跳过后续的 <code>else if</code>块或 <code>else</code>块。
如果条件操作数的求值结果为 <code>false</code>，则跳过紧跟的块，并按顺序求值后续的 <code>else if</code>条件表达式。
如果所有 <code>if</code>条件表达式和 <code>else if</code>条件表达式的求值结果均为 <code>false</code>，则执行 <code>else</code>块。
if表达式的求值结果就是所执行的块的返回值，或者如果没有块被求值那 if表达式的求值结果就是 <code>()</code>。
<code>if</code>表达式在所有情况下的类型必须一致。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let x = 3;
</span>if x == 4 {
    println!(&quot;x is four&quot;);
} else if x == 3 {
    println!(&quot;x is three&quot;);
} else {
    println!(&quot;x is something else&quot;);
}

let y = if 12 * 15 &gt; 150 {
    &quot;Bigger&quot;
} else {
    &quot;Smaller&quot;
};
assert_eq!(y, &quot;Bigger&quot;);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#if-let-expressions" id="if-let-expressions"><code>if let</code> expressions</a></h2>
<h2><a class="header" href="#if-let表达式" id="if-let表达式"><code>if let</code>表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>IfLetExpression</em> :<br />
   <code>if</code> <code>let</code> <a href="expressions/../patterns.html"><em>Pattern</em></a> <code>=</code> <a href="expressions/match-expr.html"><em>Scrutinee</em></a><sub><em>排除惰性布尔运算符表达式</em></sub>
<a href="expressions/block-expr.html"><em>BlockExpression</em></a><br />
   (<code>else</code> (
<a href="expressions/block-expr.html"><em>BlockExpression</em></a>
| <em>IfExpression</em>
| <em>IfLetExpression</em> ) )<sup>?</sup></p>
</blockquote>
<p><code>if let</code>表达式在语义上类似于 <code>if</code>表达式，但是代替条件操作数的是一个关键字 <code>let</code>，再后面是一个模式、一个 <code>=</code> 和一个<a href="expressions/../glossary.html#scrutinee">检验对象(scrutinee)</a>操作数。
如果检验对象操作数的值与模式匹配，则执行相应的块。
否则，如果存在 <code>else</code>块，则继续处理后面的 <code>else</code>块。和 <code>if</code>表达式一样，<code>if let</code>表达式也可以有返回值，这个返回值是由被求值的块确定。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let dish = (&quot;Ham&quot;, &quot;Eggs&quot;);

// 此主体代码将被跳过，因为该模式被反驳
if let (&quot;Bacon&quot;, b) = dish {
    println!(&quot;Bacon is served with {}&quot;, b);
} else {
    // 这个块将被执行。
    println!(&quot;No bacon will be served&quot;);
}

// 此主体代码将被执行
if let (&quot;Ham&quot;, b) = dish {
    println!(&quot;Ham is served with {}&quot;, b);
}

if let _ = 5 {
    println!(&quot;不可反驳型的模式总是会匹配成功的&quot;);
}
<span class="boring">}
</span></code></pre></pre>
<p><code>if</code>表达式和 <code>if let</code>表达式能混合使用:</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = Some(3);
let a = if let Some(1) = x {
    1
} else if x == Some(2) {
    2
} else if let Some(y) = x {
    y
} else {
    -1
};
assert_eq!(a, 3);
<span class="boring">}
</span></code></pre></pre>
<p><code>if let</code>表达式等价于<a href="expressions/match-expr.html">match表达式</a>，例如：</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">if let PATS = EXPR {
    /* body */
} else {
    /*else */
}
</code></pre>
<p>is equivalent to</p>
<!-- ignore: expansion example -->
<pre><code class="language-rust ignore">match EXPR {
    PATS =&gt; { /* body */ },
    _ =&gt; { /* else */ },    // 如果没有 else块，这相当于 `()`
}
</code></pre>
<p>可以使用操作符 <code>|</code> 指定多个模式。
这与匹配(<code>match</code>)表达式中的 <code>|</code> 具有相同的语义：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum E {
    X(u8),
    Y(u8),
    Z(u8),
}
let v = E::Y(12);
if let E::X(n) | E::Y(n) = v {
    assert_eq!(n, 12);
}
<span class="boring">}
</span></code></pre></pre>
<p><code>if let</code>表达式不能是<a href="expressions/operator-expr.html#lazy-boolean-operators">惰性布尔运算符表达式</a>。
使用惰性布尔运算符的效果是不明确的，因为 Rust 里一个新特性（if-let执行链(if-let chains)的实现-请参阅<a href="https://github.com/rust-lang/rfcs/blob/master/text/2497-if-let-chains.md#rollout-plan-and-transitioning-to-rust-2018">eRFC 2947</a>）正被提上日程。
当确实需要惰性布尔运算符表达式时，可以像下面一样使用圆括号来实现：</p>
<!-- ignore: psuedo code -->
<pre><code class="language-rust ignore">// Before...
if let PAT = EXPR &amp;&amp; EXPR { .. }

// After...
if let PAT = ( EXPR &amp;&amp; EXPR ) { .. }

// Before...
if let PAT = EXPR || EXPR { .. }

// After...
if let PAT = ( EXPR || EXPR ) { .. }
</code></pre>
<h1><a class="header" href="#match-expressions" id="match-expressions"><code>match</code> expressions</a></h1>
<h1><a class="header" href="#匹配match表达式" id="匹配match表达式">匹配(<code>match</code>)表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/match-expr.md">match-expr.md</a><br />
commit: 0e7115d32fec1a9f11208e0353457f528e36e0e8 <br />
本章译文最后维护日期：2021-6-27</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>MatchExpression</em> :<br />
   <code>match</code> <em>Scrutinee</em> <code>{</code><br />
      <a href="expressions/../attributes.html"><em>InnerAttribute</em></a><sup>*</sup><br />
      <em>MatchArms</em><sup>?</sup><br />
   <code>}</code></p>
<p><em>Scrutinee</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a><sub><em>排除结构体表达式</em></sub></p>
<p><em>MatchArms</em> :<br />
   ( <em>MatchArm</em> <code>=&gt;</code>
( <a href="expressions/../expressions.html"><em>ExpressionWithoutBlock</em></a> <code>,</code>
| <a href="expressions/../expressions.html"><em>ExpressionWithBlock</em></a> <code>,</code><sup>?</sup> )
)<sup>*</sup><br />
   <em>MatchArm</em> <code>=&gt;</code> <a href="expressions/../expressions.html"><em>Expression</em></a> <code>,</code><sup>?</sup></p>
<p><em>MatchArm</em> :<br />
   <a href="expressions/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> <a href="expressions/../patterns.html"><em>Pattern</em></a> <em>MatchArmGuard</em><sup>?</sup></p>
<p><em>MatchArmGuard</em> :<br />
   <code>if</code> <a href="expressions/../expressions.html"><em>Expression</em></a></p>
</blockquote>
<p><em>匹配(<code>match</code>)表达式</em>在模式(pattern)上建立代码逻辑分支(branch)。
匹配的确切形式取决于其应用的<a href="expressions/../patterns.html">模式</a>。
一个匹配(<code>match</code>)表达式带有一个要与模式进行比较的 <em><a href="expressions/../glossary.html#scrutinee">检验对象</a>(scrutinee)表达式</em>。
检验对象表达式和模式必须具有相同的类型。</p>
<p>根据检验对象表达式是<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式或值表达式</a>，匹配(<code>match</code>)的行为表现会有所不同。
如果检验对象表达式是一个<a href="expressions/../expressions.html#place-expressions-and-value-expressions">值表达式</a>，则这个表达式首先会在被求值到一个临时内存位置，然后将这个结果值按顺序与匹配臂(arms)中的模式进行比较，直到找到一个成功的匹配。
第一个匹配成功的模式所在的匹配臂会被选中为当前匹配(<code>match</code>)的分支目标，然后以该模式绑定的变量为中介，（把它从检验对象那里匹配到的变量值）转赋值给该匹配臂的块中的局部变量，然后控制流进入该块。</p>
<p>当检验对象表达式是一个<a href="expressions/../expressions.html#place-expressions-and-value-expressions">位置表达式</a>时，此匹配(<code>match</code>)表达式不用先去内存上分配一个临时位置；但是，按值匹配的绑定方式(by-value binding)会复制或移动这个（位置表达式代表的）内存位置里面的值。
如果可能，最好还是在位置表达式上进行匹配，因为这种匹配的生存期继承了该位置表达式的生存期，而不会（让其生存期仅）局限于此匹配的内部。</p>
<p>匹配(<code>match</code>)表达式的一个示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = 1;

match x {
    1 =&gt; println!(&quot;one&quot;),
    2 =&gt; println!(&quot;two&quot;),
    3 =&gt; println!(&quot;three&quot;),
    4 =&gt; println!(&quot;four&quot;),
    5 =&gt; println!(&quot;five&quot;),
    _ =&gt; println!(&quot;something else&quot;),
}
<span class="boring">}
</span></code></pre></pre>
<p>模式中绑定到的变量的作用域可以覆盖到匹配守卫(match guard)和匹配臂的表达式里。
<a href="expressions/../patterns.html#binding-modes">变量绑定方式</a>（移动、复制或引用）取决于使用的具体模式。</p>
<p>可以使用操作符 <code>|</code> 连接多个匹配模式。
每个模式将按照从左到右的顺序进行测试，直到找到一个成功的匹配。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = 9;
let message = match x {
    0 | 1  =&gt; &quot;not many&quot;,
    2 ..= 9 =&gt; &quot;a few&quot;,
    _      =&gt; &quot;lots&quot;
};

assert_eq!(message, &quot;a few&quot;);

// 演示模式匹配顺序。
struct S(i32, i32);

match S(1, 2) {
    S(z @ 1, _) | S(_, z @ 2) =&gt; assert_eq!(z, 1),
    _ =&gt; panic!(),
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意: <code>2..=9</code> 是一个<a href="expressions/../patterns.html#range-patterns">区间(Range)模式</a>，不是一个<a href="expressions/range-expr.html">区间表达式</a>。
因此，只有区间模式支持的区间类型才能在匹配臂中使用。</p>
</blockquote>
<p>每个 <code>|</code> 分隔的模式里出现的变量绑定必须出现在匹配臂的所有模式里。
相同名称的绑定变量必须具有相同的类型和相同的变量绑定模式。</p>
<h2><a class="header" href="#match-guards" id="match-guards">Match guards</a></h2>
<h2><a class="header" href="#匹配守卫" id="匹配守卫">匹配守卫</a></h2>
<p>匹配臂可以接受*匹配守卫(Pattern guard)*来进一步改进匹配标准。
模式守卫出现在模式的后面，由关键字 <code>if</code> 后面的布尔类型表达式组成。</p>
<p>当模式匹配成功时，将执行匹配守卫表达式。
如果此表达式的计算结果为真，则此模式将进一步被确认为匹配成功。
否则，匹配将测试下一个模式，包括测试同一匹配臂中运算符 <code>|</code> 分割的后续匹配模式。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let maybe_digit = Some(0);
</span><span class="boring">fn process_digit(i: i32) { }
</span><span class="boring">fn process_other(i: i32) { }
</span>let message = match maybe_digit {
    Some(x) if x &lt; 10 =&gt; process_digit(x),
    Some(x) =&gt; process_other(x),
    None =&gt; panic!(),
};
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：使用操作符 <code>|</code> 的多次匹配可能会导致后跟的匹配守卫必须多次执行的副作用。
例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::cell::Cell;
</span>let i : Cell&lt;i32&gt; = Cell::new(0);
match 1 {
    1 | _ if { i.set(i.get() + 1); false } =&gt; {}
    _ =&gt; {}
}
assert_eq!(i.get(), 2);
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<p>匹配守卫可以引用绑定在它们前面的模式里的变量。
在对匹配守卫进行计算之前，将对检验对象内部被模式的变量匹配上的那部分进行共享引用。
在对匹配守卫进行计算时，访问守卫里的这些变量就会使用这个共享引用。只有当匹配守卫最终计算为真时，此共享引用的值才会从检验对象内部移动或复制到相应的匹配臂的变量中。
这使得共享借用可以在守卫内部使用，还不会在守卫不匹配的情况下将值移出检验对象。
此外，通过在计算匹配守卫的同时持有共享引用，也可以防止匹配守卫内部意外修改检验对象。</p>
<h2><a class="header" href="#attributes-on-match-arms" id="attributes-on-match-arms">Attributes on match arms</a></h2>
<h2><a class="header" href="#匹配臂上的属性" id="匹配臂上的属性">匹配臂上的属性</a></h2>
<p>在匹配臂上允许使用外部属性，但在匹配臂上只有 <a href="expressions/../conditional-compilation.html"><code>cfg</code></a>、<a href="expressions/../attributes/codegen.html#the-cold-attribute"><code>cold</code></a> 和 <a href="expressions/../attributes/diagnostics.html#lint-check-attributes">lint检查类属性</a>这些属性才有意义。</p>
<p>在允许<a href="expressions/../attributes.html">块表达式上的属性</a>存在的那几种表达式上下文中，可以在匹配表达式的左括号后直接使用<a href="expressions/block-expr.html#attributes-on-block-expressions">内部属性</a>。</p>
<h1><a class="header" href="#return-expressions" id="return-expressions"><code>return</code> expressions</a></h1>
<h1><a class="header" href="#返回return表达式" id="返回return表达式">返回(<code>return</code>)表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/return-expr.md">return-expr.md</a><br />
commit: eb5290329316e96c48c032075f7dbfa56990702b <br />
本章译文最后维护日期：2021-02-21</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ReturnExpression</em> :<br />
   <code>return</code> <a href="expressions/../expressions.html"><em>Expression</em></a><sup>?</sup></p>
</blockquote>
<p>返回(return)表达式使用关键字 <code>return</code> 来标识。
对返回(<code>return</code>)表达式求值会将其参数移动到当前函数调用的指定输出位置，然后销毁当前函数的激活帧(activation frame)，并将控制权转移到此函数的调用帧(caller frame)。</p>
<p>一个返回(<code>return</code>)表达式的例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn max(a: i32, b: i32) -&gt; i32 {
    if a &gt; b {
        return a;
    }
    return b;
}
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#await-expressions" id="await-expressions">Await expressions</a></h1>
<h1><a class="header" href="#等待await表达式" id="等待await表达式">等待(await)表达式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/expressions/await-expr.md">await-expr.md</a><br />
commit: 23672971a16c69ea894bef24992b74912cfe5d25 <br />
本章译文最后维护日期：2021-4-5</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>AwaitExpression</em> :<br />
   <a href="expressions/../expressions.html"><em>Expression</em></a> <code>.</code> <code>await</code></p>
</blockquote>
<p><em>等待(await)表达式</em>挂起当前计算，直到给定的 future 准备好生成值。
等待(await)表达式的句法格式为：一个其类型实现了 <a href="https://doc.rust-lang.org/std/future/trait.Future.html">Future</a> trait 的表达式（此表达式本身被称为 <em>future操作数</em>）后跟一 <code>.</code>标记，再后跟一个 <code>await</code>关键字。</p>
<p>等待(await)表达式仅在<a href="expressions/../expressions/block-expr.html#async-context">异步上下文</a>中才能使用，例如 <a href="expressions/../items/functions.html#async-functions">异步函数(<code>async fn</code>)</a> 或 <a href="expressions/block-expr.html#async-blocks">异步(<code>async</code>)块</a>。</p>
<p>更具体地说，等待(await)表达式具有以下效果：</p>
<ol>
<li>把 future操作数求值计算到一个 <a href="https://doc.rust-lang.org/std/future/trait.Future.html">future</a>类型的 <code>tmp</code> 中；</li>
<li>使用 <a href="https://doc.rust-lang.org/std/pin/struct.Pin.html#method.new_unchecked"><code>Pin::new_unchecked</code></a> 固定住(Pin)这个 <code>tmp</code>；</li>
<li>然后通过调用 <a href="https://doc.rust-lang.org/std/future/trait.Future.html#tymethod.poll"><code>Future::poll</code></a> 方法对这个固定住的 future 进行轮询，同事将当前<a href="expressions/await-expr.html#task-context">任务上下文</a>传递给它；</li>
<li>如果轮询(<code>poll</code>)调用返回 <a href="https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending"><code>Poll::Pending</code></a>，那么这个 future 就也返回 `<em>Expression</em></li>
</ol>
<blockquote>
<p><strong>版本差异</strong>： 等待(await)表达式只能从 Rust 2018 版开始才可用</p>
</blockquote>
<h2><a class="header" href="#task-context" id="task-context">Task context</a></h2>
<h2><a class="header" href="#任务上下文" id="任务上下文">任务上下文</a></h2>
<p>任务上下文是指在对<a href="expressions/../expressions/block-expr.html#async-context">异步上下文</a>本身进行轮询时提供给当前异步上下文的<a href="https://doc.rust-lang.org/std/task/struct.Context.html">上下文(<code>Context</code>)</a>。
因为等待(<code>await</code>)表达式只能在异步上下文中才能使用，所以此时必须有一些任务上下文可用。</p>
<h2><a class="header" href="#approximate-desugaring" id="approximate-desugaring">Approximate desugaring</a></h2>
<h2><a class="header" href="#近似脱糖" id="近似脱糖">近似脱糖</a></h2>
<p>实际上,一个等待(await)表达式大致相当于如下这个非正规的脱糖过程：</p>
<!-- ignore: example expansion -->
<pre><code class="language-rust ignore">match future_operand {
    mut pinned =&gt; loop {
        let mut pin = unsafe { Pin::new_unchecked(&amp;mut pinned) };
        match Pin::future::poll(Pin::borrow(&amp;mut pin), &amp;mut current_context) {
            Poll::Ready(r) =&gt; break r,
            Poll::Pending =&gt; yield Poll::Pending,
        }
    }
}
</code></pre>
<p>其中，<code>yield</code>伪代码返回 <code>Poll::Pending</code>，当再次调用时，从该点继续执行。
变量 <code>current_context</code> 是指从异步环境中获取的上下文。</p>
<h1><a class="header" href="#patterns" id="patterns">Patterns</a></h1>
<h1><a class="header" href="#模式" id="模式">模式</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/patterns.md">patterns.md</a><br />
commit: 100fa060ce1d2db7e4d1533efd289f9c18d08d53 <br />
本章译文最后维护日期：2021-5-6</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Pattern</em> :<br />
      <code>|</code><sup>?</sup> <em>PatternNoTopAlt</em>  ( <code>|</code> <em>PatternNoTopAlt</em> )<sup>*</sup></p>
<p><em>PatternNoTopAlt</em> :<br />
      <em>PatternWithoutRange</em><br />
   | <a href="patterns.html#range-patterns"><em>RangePattern</em></a></p>
<p><em>PatternWithoutRange</em> :<br />
      <a href="patterns.html#literal-patterns"><em>LiteralPattern</em></a><br />
   | <a href="patterns.html#identifier-patterns"><em>IdentifierPattern</em></a><br />
   | <a href="patterns.html#wildcard-pattern"><em>WildcardPattern</em></a><br />
   | <a href="patterns.html#rest-patterns"><em>RestPattern</em></a><br />
   | <a href="patterns.html#range-patterns"><em>ObsoleteRangePattern</em></a><br />
   | <a href="patterns.html#reference-patterns"><em>ReferencePattern</em></a><br />
   | <a href="patterns.html#struct-patterns"><em>StructPattern</em></a><br />
   | <a href="patterns.html#tuple-struct-patterns"><em>TupleStructPattern</em></a><br />
   | <a href="patterns.html#tuple-patterns"><em>TuplePattern</em></a><br />
   | <a href="patterns.html#grouped-patterns"><em>GroupedPattern</em></a><br />
   | <a href="patterns.html#slice-patterns"><em>SlicePattern</em></a><br />
   | <a href="patterns.html#path-patterns"><em>PathPattern</em></a><br />
   | <a href="macros.html#macro-invocation"><em>MacroInvocation</em></a></p>
</blockquote>
<p>模式基于给定数据结构去匹配值，并可选地将变量和这些结构中匹配到的值绑定起来。模式也用在变量声明上和函数（包括闭包）的参数上。</p>
<p>下面示例中的模式完成四件事：</p>
<ul>
<li>测试 <code>person</code> 是否在其 <code>car</code>字段中填充了内容。</li>
<li>测试 <code>person</code> 的 <code>age</code>字段（的值）是否在 13 到 19 之间，并将其值绑定到给定的变量 <code>person_age</code> 上。</li>
<li>将对 <code>name</code>字段的引用绑定到给定变量 <code>person_name</code> 上。</li>
<li>忽略 <code>person</code> 的其余字段。其余字段可以有任何值，并且不会绑定到任何变量上。</li>
</ul>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Car;
</span><span class="boring">struct Computer;
</span><span class="boring">struct Person {
</span><span class="boring">    name: String,
</span><span class="boring">    car: Option&lt;Car&gt;,
</span><span class="boring">    computer: Option&lt;Computer&gt;,
</span><span class="boring">    age: u8,
</span><span class="boring">}
</span><span class="boring">let person = Person {
</span><span class="boring">    name: String::from(&quot;John&quot;),
</span><span class="boring">    car: Some(Car),
</span><span class="boring">    computer: None,
</span><span class="boring">    age: 15,
</span><span class="boring">};
</span>if let
    Person {
        car: Some(_),
        age: person_age @ 13..=19,
        name: ref person_name,
        ..
    } = person
{
    println!(&quot;{} has a car and is {} years old.&quot;, person_name, person_age);
}
<span class="boring">}
</span></code></pre></pre>
<p>模式用于：</p>
<ul>
<li><a href="statements.html#let%E8%AF%AD%E5%8F%A5"><code>let</code>声明</a></li>
<li><a href="items/functions.html">函数</a>和<a href="expressions/closure-expr.html">闭包</a>的参数。</li>
<li><a href="expressions/match-expr.html">匹配(<code>match</code>)表达式</a></li>
<li><a href="expressions/if-expr.html"><code>if let</code>表达式</a></li>
<li><a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code>表达式</a></li>
<li><a href="expressions/loop-expr.html#iterator-loops"><code>for</code>表达式</a></li>
</ul>
<h2><a class="header" href="#destructuring" id="destructuring">Destructuring</a></h2>
<h2><a class="header" href="#解构" id="解构">解构</a></h2>
<p>模式可用于<em>解构</em><a href="items/structs.html">结构体(<code>struct</code>)</a>、<a href="items/enumerations.html">枚举(<code>enum</code>)</a>和<a href="types/tuple.html">元组</a>。解构将一个值分解成它的组件组成，使用的句法与创建此类值时的几乎相同。在<a href="glossary.html#scrutinee">检验对象</a>表达式的类型为结构体(<code>struct</code>)、枚举(<code>enum</code>)或元组(<code>tuple</code>)的模式中，占位符(<code>_</code>) 代表<em>一个</em>数据字段，而通配符 <code>..</code> 代表特定变量/变体(variant)的<em>所有</em>剩余字段。当使用字段的名称（而不是字段序号）来解构数据结构时，允许将 <code>fieldname</code> 当作 <code>fieldname: fieldname</code> 的简写形式书写。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">enum Message {
</span><span class="boring">    Quit,
</span><span class="boring">    WriteString(String),
</span><span class="boring">    Move { x: i32, y: i32 },
</span><span class="boring">    ChangeColor(u8, u8, u8),
</span><span class="boring">}
</span><span class="boring">let message = Message::Quit;
</span>match message {
    Message::Quit =&gt; println!(&quot;Quit&quot;),
    Message::WriteString(write) =&gt; println!(&quot;{}&quot;, &amp;write),
    Message::Move{ x, y: 0 } =&gt; println!(&quot;move {} horizontally&quot;, x),
    Message::Move{ .. } =&gt; println!(&quot;other move&quot;),
    Message::ChangeColor { 0: red, 1: green, 2: _ } =&gt; {
        println!(&quot;color change, red: {}, green: {}&quot;, red, green);
    }
};
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#refutability" id="refutability">Refutability</a></h2>
<h2><a class="header" href="#可反驳性" id="可反驳性">可反驳性</a></h2>
<p>当一个模式有可能与它所匹配的值不匹配时，我们就说它是<em>可反驳型的(refutable)</em>。也就是说，*不可反驳型(irrefutable)*模式总是能与它们所匹配的值匹配成功。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let (x, y) = (1, 2);               // &quot;(x, y)&quot; 是一个不可反驳型模式

if let (a, 3) = (1, 2) {           // &quot;(a, 3)&quot; 是可反驳型的, 将不会匹配
    panic!(&quot;Shouldn't reach here&quot;);
} else if let (a, 4) = (3, 4) {    // &quot;(a, 4)&quot; 是可反驳型的, 将会匹配
    println!(&quot;Matched ({}, 4)&quot;, a);
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#literal-patterns" id="literal-patterns">Literal patterns</a></h2>
<h2><a class="header" href="#字面量模式" id="字面量模式">字面量模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>LiteralPattern</em> :<br />
      <a href="tokens.html#boolean-literals">BOOLEAN_LITERAL</a><br />
   | <a href="tokens.html#character-literals">CHAR_LITERAL</a><br />
   | <a href="tokens.html#byte-literals">BYTE_LITERAL</a><br />
   | <a href="tokens.html#string-literals">STRING_LITERAL</a><br />
   | <a href="tokens.html#raw-string-literals">RAW_STRING_LITERAL</a><br />
   | <a href="tokens.html#byte-string-literals">BYTE_STRING_LITERAL</a><br />
   | <a href="tokens.html#raw-byte-string-literals">RAW_BYTE_STRING_LITERAL</a><br />
   | <code>-</code><sup>?</sup> <a href="tokens.html#integer-literals">INTEGER_LITERAL</a><br />
   | <code>-</code><sup>?</sup> <a href="tokens.html#floating-point-literals">FLOAT_LITERAL</a></p>
</blockquote>
<p><em>字面量模式</em>匹配的值与字面量所创建的值完全相同。由于负数不是<a href="expressions/literal-expr.html">字面量</a>，（特设定）字面量模式也接受字面量前的可选负号，它的作用类似于否定运算符。</p>
<div class="warning">
<p>浮点字面量目前还可以使用，但是由于它们在数值比较时带来的复杂性，在将来的 Rust 版本中，它们将被禁止用于字面量模式(参见 <a href="https://github.com/rust-lang/rust/issues/41620">issue #41620</a>)。</p>
</div>
<p>字面量模式总是可以反驳型的。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>for i in -2..5 {
    match i {
        -1 =&gt; println!(&quot;It's minus one&quot;),
        1 =&gt; println!(&quot;It's a one&quot;),
        2|4 =&gt; println!(&quot;It's either a two or a four&quot;),
        _ =&gt; println!(&quot;Matched none of the arms&quot;),
    }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#identifier-patterns" id="identifier-patterns">Identifier patterns</a></h2>
<h2><a class="header" href="#标识符模式" id="标识符模式">标识符模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>IdentifierPattern</em> :<br />
      <code>ref</code><sup>?</sup> <code>mut</code><sup>?</sup> <a href="identifiers.html">IDENTIFIER</a> (<code>@</code> <a href="patterns.html#patterns"><em>Pattern</em></a> ) <sup>?</sup></p>
</blockquote>
<p>标识符模式将它们匹配的值绑定到一个变量上。此标识符在该模式中必须是唯一的。该变量会在作用域中遮蔽任何同名的变量。这种绑定的作用域取决于使用模式的上下文（例如 <code>let</code>绑定或匹配臂(<code>match</code> arm)<sup class="footnote-reference"><a href="#译注1">1</a></sup>）。</p>
<p>标识符模式只能包含一个标识符（也可能前带一个 <code>mut</code>），能匹配任何值，并将其绑定到该标识符上。最常见的标识符模式应用场景就是用在变量声明上和用在函数（包括闭包）的参数上。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut variable = 10;
fn sum(x: i32, y: i32) -&gt; i32 {
<span class="boring">   x + y
</span><span class="boring">}
</span><span class="boring">}
</span></code></pre></pre>
<p>要将模式匹配到的值绑定到变量上，也可使用句法 <code>variable @ subpattern</code>。例如，下面示例中将值 2 绑定到 <code>e</code> 上（不是整个区间(range)：这里的区间是一个区间子模式(range subpattern)）。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = 2;

match x {
    e @ 1 ..= 5 =&gt; println!(&quot;got a range element {}&quot;, e),
    _ =&gt; println!(&quot;anything&quot;),
}
<span class="boring">}
</span></code></pre></pre>
<p>默认情况下，标识符模式里变量会和匹配到的值的一个拷贝副本绑定，或匹配值自身移动过来和变量完成绑定，具体是使用拷贝语义还是移动语义取决于匹配到的值是否实现了 <a href="special-types-and-traits.html#copy"><code>Copy</code></a>。也可以通过使用关键字 <code>ref</code> 将变量和值的引用绑定，或者使用 <code>ref mut</code> 将变量和值的可变引用绑定。示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let a = Some(10);
</span>match a {
    None =&gt; (),
    Some(value) =&gt; (),
}

match a {
    None =&gt; (),
    Some(ref value) =&gt; (),
}
<span class="boring">}
</span></code></pre></pre>
<p>在第一个匹配表达式中，值被拷贝（或移动）（到变量 <code>value</code> 上）。在第二个匹配中，对相同内存位置的引用被绑定到变量上。之所以需要这种句法，是因为在解构子模式(destructuring subpatterns)里，操作符 <code>&amp;</code> 不能应用在值的字段上。例如，以下内容无效：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Person {
</span><span class="boring">   name: String,
</span><span class="boring">   age: u8,
</span><span class="boring">}
</span><span class="boring">let value = Person { name: String::from(&quot;John&quot;), age: 23 };
</span>if let Person { name: &amp;person_name, age: 18..=150 } = value { }
<span class="boring">}
</span></code></pre></pre>
<p>要使其有效，请按如下方式编写代码：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Person {
</span><span class="boring">   name: String,
</span><span class="boring">   age: u8,
</span><span class="boring">}
</span><span class="boring">let value = Person { name: String::from(&quot;John&quot;), age: 23 };
</span>if let Person { name: ref person_name, age: 18..=150 } = value { }
<span class="boring">}
</span></code></pre></pre>
<p>这里，<code>ref</code> 不是被匹配的一部分。这里它唯一的目的就是使变量和匹配值的引用绑定起来，而不是潜在地拷贝或移动匹配到的内容。</p>
<p><a href="patterns.html#path-patterns">路径模式(Path pattern)</a>优先于标识符模式。如果给某个标识符指定了 <code>ref</code> 或 <code>ref mut</code>，同时该标识符又遮蔽了某个常量，这会导致错误。</p>
<p>如果 <code>@</code>子模式是不可反驳型的或未指定子模式，则标识符模式是不可反驳型的。</p>
<h3><a class="header" href="#binding-modes" id="binding-modes">Binding modes</a></h3>
<h3><a class="header" href="#绑定方式" id="绑定方式">绑定方式</a></h3>
<p>基于人类工程学的考虑，为了让引用和匹配值的绑定更容易一些，模式会自动选择不同的<em>绑定方式</em>。当引用值与非引用模式匹配时，这将自动地被视为 <code>ref</code> 或 <code>ref mut</code> 绑定方式。示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x: &amp;Option&lt;i32&gt; = &amp;Some(3);
if let Some(y) = x {
    // y 被转换为`ref y` ，其类型为 &amp;i32
}
<span class="boring">}
</span></code></pre></pre>
<p>*非引用模式(Non-reference patterns)*包括<strong>除</strong>上面这种绑定模式和后面会讲到的<a href="patterns.html#wildcard-pattern">通配符模式</a>（<code>_</code>）、匹配引用类型的<a href="patterns.html#path-patterns">常量(<code>const</code>)模式</a>和<a href="patterns.html#reference-patterns">引用模式</a>这些模式以外的所有模式。</p>
<p>如果绑定模式(binding pattern)中没有显式地包含 <code>ref</code>、<code>ref mut</code>、<code>mut</code>，那么它将使用<em>默认绑定方式</em>来确定如何绑定变量。默认绑定方式以使用移动语义的“移动(move)”方式开始。当匹配一个模式时，编译器对模式从外到内逐层匹配。每次非引用模式和引用匹配上了时，引用都会自动解引用出最后的值，并更新默认绑定方式，再进行最终的匹配。此时引用会将默认绑定方式设置为 <code>ref</code> 方式。可变引用会将模式设置为 <code>ref mut</code> 方式，除非绑定方式已经是 <code>ref</code> 了（在这种情况下它仍然是 <code>ref</code> 方式）。如果自动解引用解出的值仍然是引用，则会重复解引用。<sup class="footnote-reference"><a href="#译注2">2</a></sup></p>
<p>移动语义的绑定方式和引用语义的绑定方式可以在同一个模式中混合使用，这样做会导致绑定对象的部分被移走，并且之后无法再使用该对象。这只适用于类型无法拷贝的情况下。</p>
<p>下面的示例中，<code>name</code> 被移出了 <code>person</code>，因此如果再试图把 <code>person</code> 作为一个整体使用，或再次使用 <code>person.name</code>，将会因为*部分移出(partial move)*的问题而报错。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Person {
</span><span class="boring">   name: String,
</span><span class="boring">   age: u8,
</span><span class="boring">}
</span><span class="boring">let person = Person{ name: String::from(&quot;John&quot;), age: 23 };
</span>// 在 `age` 被引用绑定的情况下，`name` 被从 person 中移出
let Person { name, ref age } = person;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#wildcard-pattern" id="wildcard-pattern">Wildcard pattern</a></h2>
<h2><a class="header" href="#通配符模式" id="通配符模式">通配符模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>WildcardPattern</em> :<br />
   <code>_</code></p>
</blockquote>
<p><em>通配符模式</em>（下划线符号）能与任何值匹配。常用它来忽略那些无关紧要的值。在其他模式中使用该模式时，它匹配单个数据字段（与和匹配所有其余字段的 <code>..</code> 相对）。与标识符模式不同，它不会复制、移动或借用它匹配的值。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let x = 20;
</span>let (a, _) = (10, x);   // x 一定会被 _ 匹配上
<span class="boring">assert_eq!(a, 10);
</span>
// 忽略一个函数/闭包参数
let real_part = |a: f64, _: f64| { a };

// 忽略结构体的一个字段
<span class="boring">struct RGBA {
</span><span class="boring">   r: f32,
</span><span class="boring">   g: f32,
</span><span class="boring">   b: f32,
</span><span class="boring">   a: f32,
</span><span class="boring">}
</span><span class="boring">let color = RGBA{r: 0.4, g: 0.1, b: 0.9, a: 0.5};
</span>let RGBA{r: red, g: green, b: blue, a: _} = color;
<span class="boring">assert_eq!(color.r, red);
</span><span class="boring">assert_eq!(color.g, green);
</span><span class="boring">assert_eq!(color.b, blue);
</span>
// 能接收带任何值的任何 Some
<span class="boring">let x = Some(10);
</span>if let Some(_) = x {}
<span class="boring">}
</span></code></pre></pre>
<p>通配符模式总是不可反驳型的。</p>
<h2><a class="header" href="#rest-patterns" id="rest-patterns">Rest patterns</a></h2>
<h2><a class="header" href="#剩余模式" id="剩余模式">剩余模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>RestPattern</em> :<br />
   <code>..</code></p>
</blockquote>
<p><em>剩余模式</em>（<code>..</code> token）充当匹配长度可变的模式(variable-length pattern)，它匹配之前之后没有匹配的零个或多个元素。它只能在<a href="patterns.html#tuple-patterns">元组</a>模式、<a href="patterns.html#tuple-struct-patterns">元组结构体</a>模式和<a href="patterns.html#slice-patterns">切片</a>模式中使用，并且只能作为这些模式中的一个元素出现一次。当作为<a href="patterns.html#identifier-patterns">标识符模式</a>的子模式时，它也可出现在<a href="patterns.html#slice-patterns">切片模式</a>里。</p>
<p>剩余模式总是不可反驳型的。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let words = vec![&quot;a&quot;, &quot;b&quot;, &quot;c&quot;];
</span><span class="boring">let slice = &amp;words[..];
</span>match slice {
    [] =&gt; println!(&quot;slice is empty&quot;),
    [one] =&gt; println!(&quot;single element {}&quot;, one),
    [head, tail @ ..] =&gt; println!(&quot;head={} tail={:?}&quot;, head, tail),
}

match slice {
    // 忽略除最后一个元素以外的所有元素，并且最后一个元素必须是 &quot;!&quot;.
    [.., &quot;!&quot;] =&gt; println!(&quot;!!!&quot;),

    // `start` 是除最后一个元素之外的所有元素的一个切片，最后一个元素必须是 “z”。
    [start @ .., &quot;z&quot;] =&gt; println!(&quot;starts with: {:?}&quot;, start),

    // `end` 是除第一个元素之外的所有元素的一个切片，第一个元素必须是 “a”
    [&quot;a&quot;, end @ ..] =&gt; println!(&quot;ends with: {:?}&quot;, end),

    rest =&gt; println!(&quot;{:?}&quot;, rest),
}

if let [.., penultimate, _] = slice {
    println!(&quot;next to last is {}&quot;, penultimate);
}

<span class="boring">let tuple = (1, 2, 3, 4, 5);
</span>// 剩余模式也可是在元组和元组结构体模式中使用。
match tuple {
    (1, .., y, z) =&gt; println!(&quot;y={} z={}&quot;, y, z),
    (.., 5) =&gt; println!(&quot;tail must be 5&quot;),
    (..) =&gt; println!(&quot;matches everything else&quot;),
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#range-patterns" id="range-patterns">Range patterns</a></h2>
<h2><a class="header" href="#区间模式" id="区间模式">区间模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>RangePattern</em> :<br />
   <em>RangePatternBound</em> <code>..=</code> <em>RangePatternBound</em></p>
<p><em>ObsoleteRangePattern</em> :(译者注：废弃的区间模式句法/产生式) \ 
   <em>RangePatternBound</em> <code>...</code> <em>RangePatternBound</em></p>
<p><em>RangePatternBound</em> :<br />
      <a href="tokens.html#character-literals">CHAR_LITERAL</a><br />
   | <a href="tokens.html#byte-literals">BYTE_LITERAL</a><br />
   | <code>-</code><sup>?</sup> <a href="tokens.html#integer-literals">INTEGER_LITERAL</a><br />
   | <code>-</code><sup>?</sup> <a href="tokens.html#floating-point-literals">FLOAT_LITERAL</a><br />
   | <a href="paths.html#paths-in-expressions"><em>PathInExpression</em></a><br />
   | <a href="paths.html#qualified-paths"><em>QualifiedPathInExpression</em></a></p>
</blockquote>
<p>区间模式匹配在其上下边界定义的封闭区间内的值。例如，一个模式 <code>'m'..='p'</code> 将只能匹配值<code>'m'</code>、<code>'n'</code>、<code>'o'</code> 和 <code>'p'</code>。它的边界值可以是字面量，也可以是指向常量值的路径。</p>
<p>一个模式 a <code>..=</code> b 必须总是有 a ≤ b。例如，<code>10..=0</code> 这样的区间模式是错误的。</p>
<p>保留 <code>...</code>句法只是为了向后兼容。</p>
<p>区间模式只适用于标量类型(scalar type)。可接受的类型有：</p>
<ul>
<li>整型（u8、i8、u16、i16、usize、isize ...）。</li>
<li>字符型（char）。</li>
<li>浮点类型（f32 和 f64）。这已被弃用，在未来版本的 Rust 中将不可用（参见 <a href="https://github.com/rust-lang/rust/issues/41620">issue #41620</a>）。</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let c = 'f';
</span>let valid_variable = match c {
    'a'..='z' =&gt; true,
    'A'..='Z' =&gt; true,
    'α'..='ω' =&gt; true,
    _ =&gt; false,
};

<span class="boring">let ph = 10;
</span>println!(&quot;{}&quot;, match ph {
    0..=6 =&gt; &quot;acid&quot;,
    7 =&gt; &quot;neutral&quot;,
    8..=14 =&gt; &quot;base&quot;,
    _ =&gt; unreachable!(),
});

// 使用指向常量值的路径：
<span class="boring">const TROPOSPHERE_MIN : u8 = 6;
</span><span class="boring">const TROPOSPHERE_MAX : u8 = 20;
</span><span class="boring">
</span><span class="boring">const STRATOSPHERE_MIN : u8 = TROPOSPHERE_MAX + 1;
</span><span class="boring">const STRATOSPHERE_MAX : u8 = 50;
</span><span class="boring">
</span><span class="boring">const MESOSPHERE_MIN : u8 = STRATOSPHERE_MAX + 1;
</span><span class="boring">const MESOSPHERE_MAX : u8 = 85;
</span><span class="boring">
</span><span class="boring">let altitude = 70;
</span><span class="boring">
</span>println!(&quot;{}&quot;, match altitude {
    TROPOSPHERE_MIN..=TROPOSPHERE_MAX =&gt; &quot;troposphere&quot;,
    STRATOSPHERE_MIN..=STRATOSPHERE_MAX =&gt; &quot;stratosphere&quot;,
    MESOSPHERE_MIN..=MESOSPHERE_MAX =&gt; &quot;mesosphere&quot;,
    _ =&gt; &quot;outer space, maybe&quot;,
});

<span class="boring">pub mod binary {
</span><span class="boring">    pub const MEGA : u64 = 1024*1024;
</span><span class="boring">    pub const GIGA : u64 = 1024*1024*1024;
</span><span class="boring">}
</span><span class="boring">let n_items = 20_832_425;
</span><span class="boring">let bytes_per_item = 12;
</span>if let size @ binary::MEGA..=binary::GIGA = n_items * bytes_per_item {
    println!(&quot;这适用并占用{}个字节&quot;, size);
}

<span class="boring">trait MaxValue {
</span><span class="boring">    const MAX: u64;
</span><span class="boring">}
</span><span class="boring">impl MaxValue for u8 {
</span><span class="boring">    const MAX: u64 = (1 &lt;&lt; 8) - 1;
</span><span class="boring">}
</span><span class="boring">impl MaxValue for u16 {
</span><span class="boring">    const MAX: u64 = (1 &lt;&lt; 16) - 1;
</span><span class="boring">}
</span><span class="boring">impl MaxValue for u32 {
</span><span class="boring">    const MAX: u64 = (1 &lt;&lt; 32) - 1;
</span><span class="boring">}
</span>// 使用限定路径：
println!(&quot;{}&quot;, match 0xfacade {
    0 ..= &lt;u8 as MaxValue&gt;::MAX =&gt; &quot;fits in a u8&quot;,
    0 ..= &lt;u16 as MaxValue&gt;::MAX =&gt; &quot;fits in a u16&quot;,
    0 ..= &lt;u32 as MaxValue&gt;::MAX =&gt; &quot;fits in a u32&quot;,
    _ =&gt; &quot;too big&quot;,
});
<span class="boring">}
</span></code></pre></pre>
<p>当区间模式匹配某（非usize 和 非isize）整型类型和字符型(<code>char</code>)的整个值域时，此模式是不可反驳型的。例如，<code>0u8..=255u8</code> 是不可反驳型的。某类整型的值区间是从该类型的最小值到该类型最大值的闭区间。字符型(<code>char</code>)的值的区间就是那些包含所有 Unicode 标量值的区间，即 <code>'\u{0000}'..='\u{D7FF}'</code> 和 <code>'\u{E000}'..='\u{10FFFF}'</code>。</p>
<h2><a class="header" href="#reference-patterns" id="reference-patterns">Reference patterns</a></h2>
<h2><a class="header" href="#引用模式" id="引用模式">引用模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ReferencePattern</em> :<br />
   (<code>&amp;</code>|<code>&amp;&amp;</code>) <code>mut</code><sup>?</sup> <a href="patterns.html#patterns"><em>PatternWithoutRange</em></a></p>
</blockquote>
<p>引用模式对当前匹配的指针做解引用，从而能借用它们：</p>
<p>例如，下面 <code>x: &amp;i32</code> 上的两个匹配是等效的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let int_reference = &amp;3;

let a = match *int_reference { 0 =&gt; &quot;zero&quot;, _ =&gt; &quot;some&quot; };
let b = match int_reference { &amp;0 =&gt; &quot;zero&quot;, _ =&gt; &quot;some&quot; };

assert_eq!(a, b);
<span class="boring">}
</span></code></pre></pre>
<p>引用模式的文法产生式(grammar production)要求必须使用 token <code>&amp;&amp;</code> 来匹配对引用的引用，因为 <code>&amp;&amp;</code> 本身是一个单独的 token，而不是两个 <code>&amp;</code> token。</p>
<blockquote>
<p>译者注：举例</p>
<pre><code>let a = Some(&amp;&amp;10);
match a {
   Some( &amp;&amp;value ) =&gt; println!(&quot;{}&quot;, value),
   None =&gt; {}
}
</code></pre>
</blockquote>
<p>引用模式中添加关键字 <code>mut</code> 可对可变引用做解引用。引用模式中的可变性标记必须与作为匹配对象的那个引用的可变性匹配。</p>
<p>引用模式总是不可反驳型的。</p>
<h2><a class="header" href="#struct-patterns" id="struct-patterns">Struct patterns</a></h2>
<h2><a class="header" href="#结构体模式" id="结构体模式">结构体模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>StructPattern</em> :<br />
   <a href="paths.html#paths-in-expressions"><em>PathInExpression</em></a> <code>{</code><br />
      <em>StructPatternElements</em> <sup>?</sup><br />
   <code>}</code></p>
<p><em>StructPatternElements</em> :<br />
      <em>StructPatternFields</em> (<code>,</code> | <code>,</code> <em>StructPatternEtCetera</em>)<sup>?</sup><br />
   | <em>StructPatternEtCetera</em></p>
<p><em>StructPatternFields</em> :<br />
   <em>StructPatternField</em> (<code>,</code> <em>StructPatternField</em>) <sup>*</sup></p>
<p><em>StructPatternField</em> :<br />
   <a href="attributes.html"><em>OuterAttribute</em></a> <sup>*</sup><br />
   (<br />
         <a href="tokens.html#tuple-index">TUPLE_INDEX</a> <code>:</code> <a href="patterns.html#patterns"><em>Pattern</em></a><br />
      | <a href="identifiers.html">IDENTIFIER</a> <code>:</code> <a href="patterns.html#patterns"><em>Pattern</em></a><br />
      | <code>ref</code><sup>?</sup> <code>mut</code><sup>?</sup> <a href="identifiers.html">IDENTIFIER</a><br />
   )</p>
<p><em>StructPatternEtCetera</em> :<br />
   <a href="attributes.html"><em>OuterAttribute</em></a> <sup>*</sup><br />
   <code>..</code></p>
</blockquote>
<p>结构体模式匹配与子模式定义的所有条件匹配的结构体值。它也被用来<a href="patterns.html#destructuring">解构</a>结构体。</p>
<p>在结构体模式中，结构体字段需通过名称、索引（对于元组结构体来说）来指代，或者通过使用 <code>..</code> 来忽略：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Point {
</span><span class="boring">    x: u32,
</span><span class="boring">    y: u32,
</span><span class="boring">}
</span><span class="boring">let s = Point {x: 1, y: 1};
</span><span class="boring">
</span>match s {
    Point {x: 10, y: 20} =&gt; (),
    Point {y: 10, x: 20} =&gt; (),    // 顺序没关系
    Point {x: 10, ..} =&gt; (),
    Point {..} =&gt; (),
}

<span class="boring">struct PointTuple (
</span><span class="boring">    u32,
</span><span class="boring">    u32,
</span><span class="boring">);
</span><span class="boring">let t = PointTuple(1, 2);
</span><span class="boring">
</span>match t {
    PointTuple {0: 10, 1: 20} =&gt; (),
    PointTuple {1: 10, 0: 20} =&gt; (),   // 顺序没关系
    PointTuple {0: 10, ..} =&gt; (),
    PointTuple {..} =&gt; (),
}
<span class="boring">}
</span></code></pre></pre>
<p>如果没使用 <code>..</code>，需要提供所有字段的详尽匹配：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Struct {
</span><span class="boring">   a: i32,
</span><span class="boring">   b: char,
</span><span class="boring">   c: bool,
</span><span class="boring">}
</span><span class="boring">let mut struct_value = Struct{a: 10, b: 'X', c: false};
</span><span class="boring">
</span>match struct_value {
    Struct{a: 10, b: 'X', c: false} =&gt; (),
    Struct{a: 10, b: 'X', ref c} =&gt; (),
    Struct{a: 10, b: 'X', ref mut c} =&gt; (),
    Struct{a: 10, b: 'X', c: _} =&gt; (),
    Struct{a: _, b: _, c: _} =&gt; (),
}
<span class="boring">}
</span></code></pre></pre>
<p><em><code>ref</code> 和/或 <code>mut</code> IDENTIFIER</em> 这样的句法格式能匹配任意值，并将其绑定到与给定字段同名的变量上。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Struct {
</span><span class="boring">   a: i32,
</span><span class="boring">   b: char,
</span><span class="boring">   c: bool,
</span><span class="boring">}
</span><span class="boring">let struct_value = Struct{a: 10, b: 'X', c: false};
</span><span class="boring">
</span>let Struct{a: x, b: y, c: z} = struct_value;          // 解构所有的字段
<span class="boring">}
</span></code></pre></pre>
<p>当一个结构体模式的子模式是可反驳型的，那这个结构体模式就是可反驳型的。</p>
<h2><a class="header" href="#tuple-struct-patterns" id="tuple-struct-patterns">Tuple struct patterns</a></h2>
<h2><a class="header" href="#元组结构体模式" id="元组结构体模式">元组结构体模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TupleStructPattern</em> :<br />
   <a href="paths.html#paths-in-expressions"><em>PathInExpression</em></a> <code>(</code> <em>TupleStructItems</em><sup>?</sup> <code>)</code></p>
<p><em>TupleStructItems</em> :<br />
   <a href="patterns.html#patterns"><em>Pattern</em></a> ( <code>,</code> <a href="patterns.html#patterns"><em>Pattern</em></a> )<sup>*</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p>元组结构体模式匹配元组结构体值和枚举值，这些值将与该模式的子模式定义的所有条件进行匹配。它还被用于<a href="patterns.html#destructuring">解构</a>元组结构体值或枚举值。</p>
<p>当元组结构体模式的一个子模式是可反驳型的，则该元组结构体模式就是可反驳型的。</p>
<h2><a class="header" href="#tuple-patterns" id="tuple-patterns">Tuple patterns</a></h2>
<h2><a class="header" href="#元组模式" id="元组模式">元组模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TuplePattern</em> :<br />
   <code>(</code> <em>TuplePatternItems</em><sup>?</sup> <code>)</code></p>
<p><em>TuplePatternItems</em> :<br />
      <a href="patterns.html#patterns"><em>Pattern</em></a> <code>,</code><br />
   | <a href="patterns.html#rest-patterns"><em>RestPattern</em></a><br />
   | <a href="patterns.html#patterns"><em>Pattern</em></a> (<code>,</code> <a href="patterns.html#patterns"><em>Pattern</em></a>)<sup>+</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p>元组模式匹配与子模式定义的所有条件匹配的元组值。它们还被用来<a href="patterns.html#destructuring">解构</a>元组值。</p>
<p>内部只带有一个<a href="patterns.html#rest-patterns">剩余模式</a>(<em>RestPattern</em>)的元组句法形式 <code>(..)</code> 是一种内部不需要逗号分割的特殊匹配形式，它可以匹配任意长度的元组。</p>
<p>当元组模式的一个子模式是可反驳型的，那该元组模式就是可反驳型的。</p>
<p>使用元组模式的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let pair = (10, &quot;ten&quot;);
let (a, b) = pair;

assert_eq!(a, 10);
assert_eq!(b, &quot;ten&quot;);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#grouped-patterns" id="grouped-patterns">Grouped patterns</a></h2>
<h2><a class="header" href="#分组模式" id="分组模式">分组模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>GroupedPattern</em> :<br />
   <code>(</code> <a href="patterns.html#patterns"><em>Pattern</em></a> <code>)</code></p>
</blockquote>
<p>将模式括在圆括号内可用来显式控制复合模式的优先级。例如，像 <code>&amp;0..=5</code> 这样的引用模式和区间模式相邻就会引起歧义，这时可以用圆括号来消除歧义。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let int_reference = &amp;3;
match int_reference {
    &amp;(0..=5) =&gt; (),
    _ =&gt; (),
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#slice-patterns" id="slice-patterns">Slice patterns</a></h2>
<h2><a class="header" href="#切片模式" id="切片模式">切片模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>SlicePattern</em> :<br />
   <code>[</code> <em>SlicePatternItems</em><sup>?</sup> <code>]</code></p>
<p><em>SlicePatternItems</em> :<br />
   <a href="patterns.html#patterns"><em>Pattern</em></a> (<code>,</code> <a href="patterns.html#patterns"><em>Pattern</em></a>)<sup>*</sup> <code>,</code><sup>?</sup></p>
</blockquote>
<p>切片模式可以匹配固定长度的数组和动态长度的切片。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 固定长度
let arr = [1, 2, 3];
match arr {
    [1, _, _] =&gt; &quot;从 1 开始&quot;,
    [a, b, c] =&gt; &quot;从其他值开始&quot;,
};
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 动态长度
let v = vec![1, 2, 3];
match v[..] {
    [a, b] =&gt; { /* 这个匹配臂不适用，因为长度不匹配 */ }
    [a, b, c] =&gt; { /* 这个匹配臂适用 */ }
    _ =&gt; { /* 这个通配符是必需的，因为长度不是编译时可知的 */ }
};
<span class="boring">}
</span></code></pre></pre>
<p>在匹配数组时，只要每个元素是不可反驳型的，切片模式就是不可反驳型的。当匹配切片时，只有单个 <code>..</code> <a href="patterns.html#rest-patterns">剩余模式</a>或带有 <code>..</code>（剩余模式）作为子模式的<a href="patterns.html#identifier-patterns">标识符模式</a>的情况才是不可反驳型的。</p>
<h2><a class="header" href="#path-patterns" id="path-patterns">Path patterns</a></h2>
<h2><a class="header" href="#路径模式" id="路径模式">路径模式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>PathPattern</em> :<br />
      <a href="paths.html#paths-in-expressions"><em>PathInExpression</em></a><br />
   | <a href="paths.html#qualified-paths"><em>QualifiedPathInExpression</em></a></p>
</blockquote>
<p><em>路径模式</em>是指向(refer to)常量值或指向没有字段的结构体或没有字段的枚举变体的模式。</p>
<p>非限定路径模式可以指向：</p>
<ul>
<li>枚举变体</li>
<li>结构体</li>
<li>常量</li>
<li>关联常量</li>
</ul>
<p>限定路径模式只能指向关联常量。</p>
<p>常量不能是联合体类型。结构体常量和枚举常量必须带有 <code>#[derive(PartialEq, Eq)]</code> 属性（不只是实现）。</p>
<p>当路径模式指向结构体或枚举变体(枚举只有一个变体)或类型为不可反驳型的常量时，该路径模式是不可反驳型的。当路径模式指向的是可反驳型常量或带有多个变体的枚举时，该路径模式是可反驳型的。</p>
<h2><a class="header" href="#or-patterns" id="or-patterns">Or-patterns</a></h2>
<h2><a class="header" href="#or模式" id="or模式">or模式</a></h2>
<p>_or模式_是能匹配两个或多个并列子模式（例如：<code>A | B | C</code>）中的一个的模式。此模式可以任意嵌套。除了 <code>let</code>绑定和函数参数（包括闭包参数）中的模式（此时句法上使用 _PatternNoTopAlt_产生式），or模式在句法上允许在任何其他模式出现的地方出现（这些模式句法上使用 _Pattern_产生式）。</p>
<h3><a class="header" href="#static-semantics" id="static-semantics">Static semantics</a></h3>
<h3><a class="header" href="#静态语义" id="静态语义">静态语义</a></h3>
<ol>
<li>
<p>假定在某个代码深度上给定任意模式 <code>p</code> 和 <code>q</code>，现假定它们组成模式 <code>p | q</code>，则以下情况会导致这种组成的非法：</p>
<ul>
<li>从 <code>p</code> 推断出的类型和从 <code>q</code> 推断出的类型不一致，或</li>
<li><code>p</code> 和 <code>q</code> 引入的绑定标识符不一样，或</li>
<li><code>p</code> 和 <code>q</code> 中引入的同名绑定标识符的类型和绑定模式中的类型不一致。</li>
</ul>
<p>前面提到的所有实例中的类型都必须是精确的，隐式的<a href="type-coercions.html">类型强转</a>在这里不适用。</p>
</li>
<li>
<p>当对表达式 <code>match e_s { a_1 =&gt; e_1, ... a_n =&gt; e_n }</code> 做类型检查时，假定在 <code>e_s</code> 内部深度为 <code>d</code> 的地方存一个表达式片段，那对于此片段，每一个匹配臂 <code>a_i</code> 都包含了一个 <code>p_i | q_i</code> 来与此段内容进行匹配，但如果表达式片段的类型与 <code>p_i | q_i</code> 的类型不一致，则该模式 <code>p_i | q_i</code> 被认为是格式错误的。</p>
</li>
<li>
<p>为了遵从匹配模式的穷尽性检查，模式 <code>p | q</code> 被认为同时覆盖了 <code>p</code> 和 <code>q</code>。对于某些构造器 <code>c(x, ..)</code> 来说，此时应用分配律能使 <code>c(p | q, ..rest)</code> 与 <code>c(p, ..rest) | c(q, ..rest)</code> 覆盖相同的一组匹配值。这个规律可以递归地应用，直到不再有形式为 <code>p | q</code>  的嵌套模式。</p>
</li>
</ol>
<p>注意这里的*“构造器”*这个用词，我们并没有特定提到它是元组结构模式，因为它本意是指任何能够生成类型的模式。这包括枚举变量、元组结构、具有命名字段的结构、数组、元组和切片。</p>
<h3><a class="header" href="#dynamic-semantics" id="dynamic-semantics">Dynamic semantics</a></h3>
<h3><a class="header" href="#动态语义" id="动态语义">动态语义</a></h3>
<ol>
<li>检查对象表达式(scrutinee expression) <code>e_s</code> 与深度为 <code>d</code> 的模式 <code>c(p | q, ..rest)</code>（这里<code>c</code>是某种构造器，<code>p</code> 和 <code>q</code> 是任意的模式，<code>rest</code> 是 <code>c</code>构造器的任意的可选因子）进行匹配的动态语义与此表达式与 <code>c(p, ..rest) | c(q, ..rest)</code> 进行匹配的语法定义相同。</li>
</ol>
<h3><a class="header" href="#precedence-with-other-undelimited-patterns" id="precedence-with-other-undelimited-patterns">Precedence with other undelimited patterns</a></h3>
<h3><a class="header" href="#无分解符模式的优先级" id="无分解符模式的优先级">无分解符模式的优先级</a></h3>
<p>如本章其他部分所示，有几种类型的模式在语法上没有定义分界符，它们包括标识符模式、引用模式和 or模式。它们组合在一起时，or模式的优先级总是最低的。这允许我们为将来可能的类型特性保留语法空间，同时也可以减少歧义。例如，<code>x @ A(..) | B(..)</code> 将导致一个错误，即 <code>x</code> 不是在所有模式中都存在绑定关系； <code>&amp;A(x) | B(x)</code>将导致不同子模式中的 <code>x</code> 之的类型不匹配。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>请仔细参研<a href="expressions/match-expr.html">匹配表达式</a>中的 MatchExpression产生式，搞清楚匹配臂(MatchArm)的位置。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">2</sup>
<p>文字叙述有些晦涩，译者举个例子：假如 <code>if let &amp;Some(y) = &amp;&amp;&amp;Some(3) {</code>，此时会首先剥掉等号两边的第一层 <code>&amp;</code>号，然后是 <code>Some(y)</code> 和 <code>&amp;&amp;Some(3)</code>匹配，此时发现是非引用模式和引用匹配上了，就再对 <code>&amp;&amp;Some(3)</code> 做重复解引用，解出 <code>Some(3)</code>，然后从外部转向内部，见到最后的变量 <code>y</code> 和检验对象 <code>3</code>，就更新 <code>y</code> 的默认绑定方式为 <code>ref</code>，所以 <code>y</code> 就匹配为 <code>&amp;3</code>；如果我们这个例子的变量 <code>y</code> 改为 <code>ref y</code>，不影响 <code>y</code> 的绑定效果；极端的情况 <code>if let &amp;Some(y) = &amp;&amp;&amp;Some(x) {</code>，如果 <code>x</code> 是可变的，那么此时 <code>y</code> 的绑定方式就是 <code>ref mut</code>，再进一步极端 <code>if let &amp;Some(ref y) = &amp;&amp;&amp;Some(x) {</code>，此时 <code>y</code> 的绑定方式仍是 <code>ref</code>。</p>
</div>
<h1><a class="header" href="#type-system" id="type-system">Type system</a></h1>
<h1><a class="header" href="#类型系统" id="类型系统">类型系统</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/type-system.md">type-system.md</a><br />
commit: 4a2bdf896cd2df370a91d14cb8ba04e326cd21db <br />
本章译文最后维护日期：2020-10-28</p>
</blockquote>
<!-- 2020-11-12-->
<!-- checked -->
<script>
(function() {
    var fragments = {
        "#boolean-type": "types/boolean.html",
        "#numeric-types": "types/numeric.html",
        "#machine-types": "types/numeric.html",
        "#machine-dependent-integer-types": "types/numeric.html#machine-dependent-integer-types",
        "#textual-types": "types/textual.html",
        "#never-type": "types/never.html",
        "#tuple-types": "types/tuple.html",
        "#array-and-slice-types": "types/array.html",
        "#struct-types": "types/struct.html",
        "#enumerated-types": "types/enum.html",
        "#union-types": "types/union.html",
        "#pointer-types": "types/pointer.html",
        "#shared-references-": "types/pointer.html#shared-references-",
        "#mutable-references-": "types/pointer.html#mutable-references-mut",
        "#raw-pointers-const-and-mut": "types/pointer.html#raw-pointers-const-and-mut",
        "#smart-pointers": "types/pointer.html#smart-pointers",
        "#function-item-types": "types/function-item.html",
        "#function-pointer-types": "types/function-pointer.html",
        "#closure-types": "types/closure.html",
        "#capture-modes": "types/closure.html#capture-modes",
        "#unique-immutable-borrows-in-captures": "types/closure.html#unique-immutable-borrows-in-captures",
        "#call-traits-and-coercions": "types/closure.html#call-traits-and-coercions",
        "#other-traits": "types/closure.html#other-traits",
        "#trait-objects": "types/trait-object.html",
        "#trait-object-lifetime-bounds": "types/trait-object.html#trait-object-lifetime-bounds",
        "#impl-trait": "types/impl-trait.html",
        "#anonymous-type-parameters": "types/impl-trait.html#anonymous-type-parameters",
        "#abstract-return-types": "types/impl-trait.html#abstract-return-types",
        "#self-types": "paths.html#self-1",
        "#inferred-type": "types/inferred.html",
        "#type-parameters": "types/parameters.html",
    };
    var target = fragments[window.location.hash];
    if (target) {
        var url = window.location.toString();
        var base = url.substring(0, url.lastIndexOf('/'));
        window.location.replace(base + "/" + target);
    }
})();
</script>
<h1><a class="header" href="#types" id="types">Types</a></h1>
<h1><a class="header" href="#类型" id="类型">类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types.md">types.md</a><br />
commit: af1cf6d3ca3b7a8c434c142148742aa912e37c34 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<p>Rust 程序中的每个变量、程序项和值都有一个类型。<em>值</em>的<em>类型</em>定义了该如何解释用于保存它的内存数据，以及定义了可以对该值执行的操作。</p>
<p>内置的类型以非平凡的方式(in nontrivial ways)紧密地集成到语言中，这种方式是不可能在用户定义的类型中模拟的。用户定义的类型功能有限。</p>
<p>内置类型列表：</p>
<ul>
<li>原生类型(primitive types):
<ul>
<li><a href="types/boolean.html">布尔型(Boolean)</a> — <code>true</code> 或 <code>false</code></li>
<li><a href="types/numeric.html">数字类(Numeric)</a> — 整型(integer) 和 浮点型(float)</li>
<li><a href="types/textual.html">文本类(Textual)</a> — 字符型(<code>char</code>) 和 字符串切片(<code>str</code>)</li>
<li><a href="types/never.html">never类型</a> — <code>!</code> — 没有值的类型</li>
</ul>
</li>
<li>序列类型(sequence types)：
<ul>
<li><a href="types/tuple.html">元组(Tuple)</a></li>
<li><a href="types/array.html">数组(Array)</a></li>
<li><a href="types/slice.html">切片(Slice)</a></li>
</ul>
</li>
<li>用户自定义类型(user-defined types)：
<ul>
<li><a href="types/struct.html">结构体(Struct)</a></li>
<li><a href="types/enum.html">枚举(Enum)</a></li>
<li><a href="types/union.html">联合体(Union)</a></li>
</ul>
</li>
<li>函数类型(function types)：
<ul>
<li><a href="types/function-item.html">函数(Functions)</a></li>
<li><a href="types/closure.html">闭包(Closures)</a></li>
</ul>
</li>
<li>指针类型(pointer types)：
<ul>
<li><a href="types/pointer.html#shared-references-">引用(References)</a></li>
<li><a href="types/pointer.html#raw-pointers-const-and-mut">裸指针(Raw pointers)</a></li>
<li><a href="types/function-pointer.html">函数指针(Function pointers)</a></li>
</ul>
</li>
<li>trait类型(Trait types):
<ul>
<li><a href="types/trait-object.html">trait对象(Trait objects)</a></li>
<li><a href="types/impl-trait.html">实现trait(Impl trait)</a></li>
</ul>
</li>
</ul>
<h2><a class="header" href="#type-expressions" id="type-expressions">Type expressions</a></h2>
<h2><a class="header" href="#类型表达式" id="类型表达式">类型表达式</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>Type</em> :<br />
      <em>TypeNoBounds</em><br />
   | <a href="types/impl-trait.html"><em>ImplTraitType</em></a><br />
   | <a href="types/trait-object.html"><em>TraitObjectType</em></a></p>
<p><em>TypeNoBounds</em> :<br />
      <a href="types.html#parenthesized-types"><em>ParenthesizedType</em></a><br />
   | <a href="types/impl-trait.html"><em>ImplTraitTypeOneBound</em></a><br />
   | <a href="types/trait-object.html"><em>TraitObjectTypeOneBound</em></a><br />
   | <a href="paths.html#paths-in-types"><em>TypePath</em></a><br />
   | <a href="types/tuple.html#tuple-types"><em>TupleType</em></a><br />
   | <a href="types/never.html"><em>NeverType</em></a><br />
   | <a href="types/pointer.html#raw-pointers-const-and-mut"><em>RawPointerType</em></a><br />
   | <a href="types/pointer.html#shared-references-"><em>ReferenceType</em></a><br />
   | <a href="types/array.html"><em>ArrayType</em></a><br />
   | <a href="types/slice.html"><em>SliceType</em></a><br />
   | <a href="types/inferred.html"><em>InferredType</em></a><br />
   | <a href="paths.html#qualified-paths"><em>QualifiedPathInType</em></a><br />
   | <a href="types/function-pointer.html"><em>BareFunctionType</em></a><br />
   | <a href="macros.html#macro-invocation"><em>MacroInvocation</em></a></p>
</blockquote>
<p>上表中的 <em>Type</em> 文法规则中定义的各种<em>类型表达式</em>都是某个具体类型的句法产生式。它们可以覆盖指代：</p>
<ul>
<li>序列类型（<a href="types/tuple.html">tuple</a>, <a href="types/array.html">array</a>, <a href="types/slice.html">slice</a>）。</li>
<li><a href="paths.html#paths-in-types">类型路径(type paths)</a>，这些包括：
<ul>
<li>原生类型（<a href="types/boolean.html">布尔型</a>, <a href="types/numeric.html">数字类类型</a>, <a href="types/textual.html">文本类类型</a>）。</li>
<li>指向<a href="items.html">程序项</a>（<a href="types/struct.html">结构体(<code>struct</code>)</a>, <a href="types/enum.html">枚举(<code>enum</code>)</a>, <a href="types/union.html">联合体(<code>union</code>)</a>, <a href="items/type-aliases.html">类型别名</a>, <a href="types/trait-object.html">trait</a>）的路径。</li>
<li><a href="paths.html#self-1"><code>Self</code>路径</a>，其中 <code>Self</code> 是实现类型。</li>
<li>泛型<a href="types/parameters.html">类型参数</a>。</li>
</ul>
</li>
<li>指针类型（<a href="types/pointer.html#shared-references-">引用</a>, <a href="types/pointer.html#raw-pointers-const-and-mut">裸指针</a>, <a href="types/function-pointer.html">函数指针</a>）。</li>
<li><a href="types/inferred.html">自动推断型类型(inferred type)</a>，就是请求编译器确定类型的类型。</li>
<li>用来消除歧义的<a href="types.html#parenthesized-types">圆括号</a>。</li>
<li>Trait类型：<a href="types/trait-object.html">trait对象(trait object)</a> 和 <a href="types/impl-trait.html">实现trait(impl trait)</a>.</li>
<li><a href="types/never.html">never</a>型(<code>!</code>)。</li>
<li>展开成类型表达式的<a href="macros.html">宏</a>。</li>
</ul>
<h3><a class="header" href="#parenthesized-types" id="parenthesized-types">Parenthesized types</a></h3>
<h3><a class="header" href="#圆括号组合类型" id="圆括号组合类型">圆括号组合类型</a></h3>
<blockquote>
<p><em>ParenthesizedType</em> :<br />
   <code>(</code> <a href="types.html#type-expressions"><em>Type</em></a> <code>)</code></p>
</blockquote>
<p>在某些情况下，类型组合在一起时可能会产生二义性。此时可以在类型周围使用元括号来避免歧义。例如，<a href="types/pointer.html#shared-references-">引用类型</a>的<a href="trait-bounds.html">类型约束</a>列表中的 <code>+</code>运算符搞不清楚其左值的边界位置在哪里，因此需要使用圆括号来明确其边界。这里需要的消歧文法就是使用 <a href="types.html#type-expressions"><em>TypeNoBounds</em></a> 句法规则替代 <a href="types.html#type-expressions"><em>Type</em></a> 句法规则。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::any::Any;
</span>type T&lt;'a&gt; = &amp;'a (dyn Any + Send);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#recursive-types" id="recursive-types">Recursive types</a></h2>
<h2><a class="header" href="#递归类型" id="递归类型">递归类型</a></h2>
<p>标称类型(nominal types) — <a href="types/struct.html">结构体(<code>struct</code>)</a>、<a href="types/enum.html">枚举(<code>enum</code>)</a>和<a href="types/union.html">联合体(<code>union</code>)</a> — 可以是递归的。也就是说，每个枚举(<code>enum</code>)变体或结构体(<code>struct</code>)或联合体(<code>union</code>)的字段可以直接或间接地指向此枚举(<code>enum</code>)或结构体(<code>struct</code>)类型本身。这种递归有一些限制：</p>
<ul>
<li>递归类型必须在递归中包含一个标称类型（不能仅是<a href="items/type-aliases.html">类型别名</a>或其他结构化的类型，如<a href="types/array.html">数组</a>或<a href="types/tuple.html">元组</a>）。因此不允许使用 <code>type Rec = &amp;'static [Rec]</code>。</li>
<li>递归类型的尺寸必须是有限的；也就是说，类型的递归字段必须是<a href="types/pointer.html">指针类型</a>。</li>
<li>递归类型的定义可以跨越模块边界，但不能跨越模块<em>可见性</em>边界或 crate 边界（为了简化模块系统和类型检查）。</li>
</ul>
<p><em>递归</em>类型及使用示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>enum List&lt;T&gt; {
    Nil,
    Cons(T, Box&lt;List&lt;T&gt;&gt;)
}

let a: List&lt;i32&gt; = List::Cons(7, Box::new(List::Cons(13, Box::new(List::Nil))));
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#boolean-type" id="boolean-type">Boolean type</a></h1>
<h1><a class="header" href="#布尔型" id="布尔型">布尔型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/boolean.md">boolean.md</a><br />
commit: 1804726424c5cbc97f3d9d4adf6236980e2ff7a1 <br />
本章译文最后维护日期：2021-2-10</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let b: bool = true;
<span class="boring">}
</span></code></pre></pre>
<p><em>布尔型</em>或<em>布尔数</em>是一种可以为*真(<code>true</code>)<em>或</em>假(<code>false</code>)*的原语数据类型。</p>
<p>这种类型的值可以使用<a href="types/../expressions/literal-expr.html">字面量表达式</a>创建，使用关键字 <code>true</code> 和 <code>false</code> 来表达对应名称的值。</p>
<p>该类型是此<a href="types/../names/preludes.html#language-prelude">语言的预导入包</a>的一部分，使用<a href="types/../names.html">名称</a> <code>bool</code> 来表示。</p>
<p>布尔型的对象<a href="types/../type-layout.html#size-and-alignment">尺寸和对齐量</a>均为1。false 的位模式为 <code>0x00</code>， true 的位模式为 <code>0x01</code>。其他的任何其他位模式的布尔型的象都是<a href="types/../behavior-considered-undefined.html">未定义的行为</a>。</p>
<p>布尔型是多种<a href="types/../expressions.html">表达式</a>的操作数的类型:</p>
<ul>
<li><a href="types/../expressions/if-expr.html#if-expressions">if表达式</a>和 <a href="types/../expressions/loop-expr.html#predicate-loops">while表达式</a>中的条件操作数</li>
<li><a href="types/../expressions/operator-expr.html#lazy-boolean-operators">惰性布尔运算表达式</a>的操作数</li>
</ul>
<blockquote>
<p><strong>注意</strong>：布尔型的行为类似于<a href="types/enum.html">枚举类型</a>，但它确实不是枚举类型。在实践中，这主要意味着构造函数不与类型相关联（例如没有 <code>bool::true</code> 这种写法）。</p>
</blockquote>
<p>和其他所有的原语类型一样，布尔型<a href="types/../items/implementations.html">实现</a>了 <a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a>、<a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a>、<a href="types/../special-types-and-traits.html#sized"><code>Sized</code></a>、<a href="types/../special-types-and-traits.html#send"><code>Send</code></a> 和 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a> 这些 <a href="types/../items/traits.html">traits</a>。</p>
<blockquote>
<p><strong>注意</strong>: 参见<a href="types/../../std/primitive.bool.html">标准库文档</a>中的相关操作运算。</p>
</blockquote>
<h2><a class="header" href="#operations-on-boolean-values" id="operations-on-boolean-values">Operations on boolean values</a></h2>
<h2><a class="header" href="#布尔运算" id="布尔运算">布尔运算</a></h2>
<!-- 这是一种模棱两可的措辞 --> 当使用带有布尔型的操作数的特定操作符表达式时，它们使用[布尔逻辑规则][boolean logic]进行计算。
<h3><a class="header" href="#logical-not" id="logical-not">Logical not</a></h3>
<h3><a class="header" href="#逻辑非" id="逻辑非">逻辑非</a></h3>
<table><thead><tr><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#negation-operators"><code>!b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td></tr>
</tbody></table>
<h3><a class="header" href="#logical-or" id="logical-or">Logical or</a></h3>
<h3><a class="header" href="#逻辑或" id="逻辑或">逻辑或</a></h3>
<table><thead><tr><th><code>a</code></th><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#arithmetic-and-logical-binary-operators"><code>a | b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>true</code></td><td><code>true</code></td></tr>
<tr><td><code>true</code></td><td><code>false</code></td><td><code>true</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td><td><code>true</code></td></tr>
<tr><td><code>false</code></td><td><code>false</code></td><td><code>false</code></td></tr>
</tbody></table>
<h3><a class="header" href="#logical-and" id="logical-and">Logical and</a></h3>
<h3><a class="header" href="#逻辑与" id="逻辑与">逻辑与</a></h3>
<table><thead><tr><th><code>a</code></th><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#arithmetic-and-logical-binary-operators"><code>a &amp; b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>true</code></td><td><code>true</code></td></tr>
<tr><td><code>true</code></td><td><code>false</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>false</code></td><td><code>false</code></td></tr>
</tbody></table>
<h3><a class="header" href="#logical-xor" id="logical-xor">Logical xor</a></h3>
<h3><a class="header" href="#逻辑异或" id="逻辑异或">逻辑异或</a></h3>
<table><thead><tr><th><code>a</code></th><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#arithmetic-and-logical-binary-operators"><code>a ^ b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>true</code></td><td><code>false</code></td><td><code>true</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td><td><code>true</code></td></tr>
<tr><td><code>false</code></td><td><code>false</code></td><td><code>false</code></td></tr>
</tbody></table>
<h3><a class="header" href="#comparisons" id="comparisons">Comparisons</a></h3>
<h3><a class="header" href="#比较" id="比较">比较</a></h3>
<table><thead><tr><th><code>a</code></th><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#comparison-operators"><code>a == b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>true</code></td><td><code>true</code></td></tr>
<tr><td><code>true</code></td><td><code>false</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>false</code></td><td><code>true</code></td></tr>
</tbody></table>
<table><thead><tr><th><code>a</code></th><th><code>b</code></th><th><a href="types/../expressions/operator-expr.html#comparison-operators"><code>a &gt; b</code></a></th></tr></thead><tbody>
<tr><td><code>true</code></td><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>true</code></td><td><code>false</code></td><td><code>true</code></td></tr>
<tr><td><code>false</code></td><td><code>true</code></td><td><code>false</code></td></tr>
<tr><td><code>false</code></td><td><code>false</code></td><td><code>false</code></td></tr>
</tbody></table>
<ul>
<li><code>a != b</code> 等同于 <code>!(a == b)</code></li>
<li><code>a &gt;= b</code> 等同于 <code>a == b | a &gt; b</code></li>
<li><code>a &lt; b</code> 等同于 <code>!(a &gt;= b)</code></li>
<li><code>a &lt;= b</code> 等同于 <code>a == b | a &lt; b</code></li>
</ul>
<h1><a class="header" href="#numeric-types" id="numeric-types">Numeric types</a></h1>
<h1><a class="header" href="#数字型" id="数字型">数字型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/mumeric.md">mumeric.md</a><br />
commit: 73ca198fb3ab52283d67d5fe28c541ee1d169f48 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<h2><a class="header" href="#integer-types" id="integer-types">Integer types</a></h2>
<h2><a class="header" href="#整型整数类型" id="整型整数类型">整型/整数类型</a></h2>
<p>无符号整数类型：</p>
<table><thead><tr><th>类型</th><th>最小值</th><th>最大值</th></tr></thead><tbody>
<tr><td><code>u8</code></td><td>0</td><td>2<sup>8</sup>-1</td></tr>
<tr><td><code>u16</code></td><td>0</td><td>2<sup>16</sup>-1</td></tr>
<tr><td><code>u32</code></td><td>0</td><td>2<sup>32</sup>-1</td></tr>
<tr><td><code>u64</code></td><td>0</td><td>2<sup>64</sup>-1</td></tr>
<tr><td><code>u128</code></td><td>0</td><td>2<sup>128</sup>-1</td></tr>
</tbody></table>
<p>有符号二进制补码整型包括：</p>
<table><thead><tr><th>类型</th><th>最小值</th><th>最大值</th></tr></thead><tbody>
<tr><td><code>i8</code></td><td>-(2<sup>7</sup>)</td><td>2<sup>7</sup>-1</td></tr>
<tr><td><code>i16</code></td><td>-(2<sup>15</sup>)</td><td>2<sup>15</sup>-1</td></tr>
<tr><td><code>i32</code></td><td>-(2<sup>31</sup>)</td><td>2<sup>31</sup>-1</td></tr>
<tr><td><code>i64</code></td><td>-(2<sup>63</sup>)</td><td>2<sup>63</sup>-1</td></tr>
<tr><td><code>i128</code></td><td>-(2<sup>127</sup>)</td><td>2<sup>127</sup>-1</td></tr>
</tbody></table>
<h2><a class="header" href="#floating-point-types" id="floating-point-types">Floating-point types</a></h2>
<h2><a class="header" href="#浮点型" id="浮点型">浮点型</a></h2>
<p>Rust 对应 IEEE 754-2008 的“binary32”和“binary64”浮点类型分别是 <code>f32</code> 和 <code>f64</code>。</p>
<h2><a class="header" href="#machine-dependent-integer-types" id="machine-dependent-integer-types">Machine-dependent integer types</a></h2>
<h2><a class="header" href="#和计算平台相关的整型" id="和计算平台相关的整型">和计算平台相关的整型</a></h2>
<p><code>usize</code>类型是一种无符号整型，其宽度与平台的指针类型的宽度相同。它可以表示进程中的每个内存地址。</p>
<p><code>isize</code>类型是一种有符号整型，其宽度与平台的指针类型的宽度相同。（Rust 规定）对象的尺寸和数组的长度的理论上限是 <code>isize</code> 的最大值。这确保了 <code>isize</code> 可以用来计算指向对象或数组内部的指针之间的差异，并且可以寻址对象中的每个字节以及末尾之后的那个字节。</p>
<p><code>usize</code> 和 <code>isize</code> 的宽度至少是 16-bits。</p>
<blockquote>
<p><strong>注意</strong>：许多 Rust 代码可能会假设指针、<code>usize</code> 和 <code>isize</code> 是 32-bit 或 64-bit 的。因此，16-bit 指针的支持是有限的，这部分支持可能需要来自库的明确关注和确认。</p>
</blockquote>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#textual-types" id="textual-types">Textual types</a></h1>
<h1><a class="header" href="#文本类类型" id="文本类类型">文本类类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/textual.md">textual.md</a><br />
commit: 9af5071f876111a09ba54a86655679de83eb464c <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<p>类型 <code>char</code> 和 <code>str</code> 用于保存文本数据。</p>
<p>字符型(<code>char</code>)的值是 <a href="http://www.unicode.org/glossary/#unicode_scalar_value">Unicode 标量(scalar)值</a>（即不是代理项(surrogate)的代码点），可以表示为 0x0000~0xD7FF 或 0xE000~0x10FFFF 范围内的 32-bit 无符号字符。创建超出此范围的字符直接触发<a href="types/../behavior-considered-undefined.html">未定义行为(Undefined Behavior)</a>。一个 <code>[char]</code> 实际上是长度为1的 UCS-4 / UTF-32 字符串。</p>
<p><code>str</code>类型的值的表示方法与 <code>[u8]</code> 相同，它是一个 8-bit 无符号字节类型的切片。但是，Rust 标准库对 <code>str</code> 做了额外的假定：<code>str</code> 上的方法会假定并确保其中的数据是有效的 UTF-8。调用 <code>str</code> 的方法来处理非UTF-8 缓冲区上的数据可能或早或晚地出现<a href="types/../behavior-considered-undefined.html">未定义行为</a>。</p>
<p>由于 <code>str</code> 是一个<a href="types/../dynamically-sized-types.html">动态尺寸类型</a>，所以它只能通过指针类型实例化，比如 <code>&amp;str</code>。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#never-type" id="never-type">Never type</a></h1>
<h1><a class="header" href="#never类型" id="never类型">never类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/never.md">never.md</a><br />
commit: 91486df597a9e8060f9c67587359e9f168dea7ef <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>NeverType</em> : <code>!</code></p>
</blockquote>
<p>never类型(<code>!</code>)是一个没有值的类型，表示永远不会完成计算的结果。<code>!</code> 的类型表达式可以强转为任何其他类型。</p>
<!-- ignore: unstable -->
<pre><code class="language-rust ignore">let x: ! = panic!();
// 可以强转为任何类型
let y: u32 = x;
</code></pre>
<p><strong>注意：</strong> never类型原本预计在1.41中稳定下来，但由于最后一分钟检测到一些意想不到的回归，该类型的稳定进程临时暂停。目前 <code>!</code>类型只能出现在函数返回类型中。有关详细信息，请参阅<a href="https://github.com/rust-lang/rust/issues/35121">议题跟踪</a>。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#tuple-types" id="tuple-types">Tuple types</a></h1>
<h1><a class="header" href="#元组类型" id="元组类型">元组类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/tuple.md">tuple.md</a><br />
commit: 80f4867bcc2baaa9bcdb650c43276cd98883389c <br />
本章译文最后维护日期：2021-07-24</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TupleType</em> :<br />
      <code>(</code> <code>)</code><br />
   | <code>(</code> ( <a href="types/../types.html#type-expressions"><em>Type</em></a> <code>,</code> )<sup>+</sup> <a href="types/../types.html#type-expressions"><em>Type</em></a><sup>?</sup> <code>)</code></p>
</blockquote>
<p><em>元组类型</em>是由其他类型的异构列表组合成的一类结构化类型<sup class="footnote-reference"><a href="#1">1</a></sup>。</p>
<p>元组类型的语法规则为一对圆括号封闭的逗号分割的类型列表。
为和<a href="types/../types.html#parenthesized-types">圆括号类型</a>区分开来，一元元组的元素类型后面需要有一个逗号。</p>
<p>元组类型的字段数量等同于其封闭的异构类型列表的长度。
字段的数量决定元组的<em>元数(arity)</em>。
有 <code>n</code> 个字段的元组叫做 <em>n元元组(n-ary tuple)</em>。
例如，有两个字段的元组就是二元元组。</p>
<p>元组的字段用它在列表中的位置数字来索引。
第一个字段索引为 <code>0</code>。
第二个字段索引为 <code>1</code>。
然后以此类推。
每个字段的类型都是元组类型列表中相同位置的类型。</p>
<p>出于方便和历史原因，不带元素(<code>()</code>)的元组类型通常被称为<em>单元(unit)<em>或</em>单元类型(unit type)</em>。
它的值也被称为<em>单元</em>或<em>单元值</em>。</p>
<p>元组类型的示例：</p>
<ul>
<li><code>()</code> (单元)</li>
<li><code>(f64, f64)</code></li>
<li><code>(String, i32)</code></li>
<li><code>(i32, String)</code> (跟前一个示例类型不一样)</li>
<li><code>(i32, f64, Vec&lt;String&gt;, Option&lt;bool&gt;)</code></li>
</ul>
<p>这种类型的值是使用<a href="types/../expressions/tuple-expr.html#tuple-expressions">元组表达式</a>来构造的。
此外，如果没有其他有意义的值可供求得/返回，很多种表达式都将生成单元值。
元组字段可以通过<a href="types/../expressions/tuple-expr.html#tuple-indexing-expressions">元组索引表达式</a>或<a href="types/../patterns.html#tuple-patterns">模式匹配</a>来访问。</p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p>结构化类型的特点就是其内部对等位置的类型如果是相等的，那么这些结构化类型就是相等的。有关元组的标称类型版本，请参见<a href="types/./struct.html">元组结构体</a>。</p>
</div>
<!-- 2021-1-10-->
<!-- checked -->
<h1><a class="header" href="#array-types" id="array-types">Array types</a></h1>
<h1><a class="header" href="#数组类型" id="数组类型">数组类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/array.md">array.md</a><br />
commit: 2f459e22ec30a94bafafe417da4e95044578df73 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ArrayType</em> :<br />
   <code>[</code> <a href="types/../types.html#type-expressions"><em>Type</em></a> <code>;</code> <a href="types/../expressions.html"><em>Expression</em></a> <code>]</code></p>
</blockquote>
<p>数组是 <code>N</code> 个类型为 <code>T</code> 的元素组成的固定长度(fixed-size)的序列，数组类型写为 <code>[T; N]</code>。长度(size)是一个计算结果为 <a href="types/numeric.html#machine-dependent-integer-types"><code>usize</code></a> 的<a href="types/../const_eval.html#constant-expressions">常量表达式</a>。</p>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 一个栈分配的数组
let array: [i32; 3] = [1, 2, 3];

// 一个堆分配的数组，被自动强转成切片
let boxed_array: Box&lt;[i32]&gt; = Box::new([1, 2, 3]);
<span class="boring">}
</span></code></pre></pre>
<p>数组的所有元素总是初始化过的，使用 Rust 中的安全(safe)方法或操作符来访问数组时总是会先做越界检查。</p>
<blockquote>
<p>注意：标准库类型 <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html"><code>Vec&lt;T&gt;</code></a> 提供了堆分配方案的可调整大小的数组类型。</p>
</blockquote>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#slice-types" id="slice-types">Slice types</a></h1>
<h1><a class="header" href="#切片类型" id="切片类型">切片类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/slice.md">slice.md</a><br />
commit: b0e0ad6490d6517c19546b1023948986578fc378 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>SliceType</em> :<br />
   <code>[</code> <a href="types/../types.html#type-expressions"><em>Type</em></a> <code>]</code></p>
</blockquote>
<p>切片是一种<a href="types/../dynamically-sized-types.html">动态尺寸类型(dynamically sized type)</a>，它代表类型为 <code>T</code> 的元素组成的数据序列的一个“视图(view)”。切片类型写为 <code>[T]</code>。</p>
<p>要使用切片类型，通常必须放在指针后面使用，例如：</p>
<ul>
<li><code>&amp;[T]</code>，共享切片('shared slice')，常被直接称为切片(<code>slice</code>)，它不拥有它指向的数据，只是借用。</li>
<li><code>&amp;mut [T]</code>，可变切片('mutable slice')，可变借用它指向的数据。</li>
<li><code>Box&lt;[T]&gt;</code>, boxed切片('boxed slice')。</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 一个堆分配的数组，被自动强转成切片
let boxed_array: Box&lt;[i32]&gt; = Box::new([1, 2, 3]);

// 数组上的（共享）切片
let slice: &amp;[i32] = &amp;boxed_array[..];
<span class="boring">}
</span></code></pre></pre>
<p>切片的所有元素总是初始化过的，使用 Rust 中的安全(safe)方法或操作符来访问切片时总是会做越界检查。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#struct-types" id="struct-types">Struct types</a></h1>
<h1><a class="header" href="#结构体类型" id="结构体类型">结构体类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/struct.md">struct.md</a><br />
commit: 8a98437835db5f3cf57044aedcd1e00bd0d889f9 <br />
本章译文最后维护日期：2021-1-17</p>
</blockquote>
<p>结构体(<code>struct</code>)<em>类型</em>是其由他类型异构产生的类型，这些其他类型被称为结构体类型的字段。<sup class="footnote-reference"><a href="#structtype">1</a></sup></p>
<p>结构体(<code>struct</code>)的实例可以用<a href="types/../expressions/struct-expr.html">结构体表达式</a>来构造。</p>
<p>默认情况下，结构体(<code>struct</code>)的内存布局是未定义的（默认允许进行一些编译器优化，比如字段重排），但也可以使用<a href="types/../type-layout.html#representations"><code>repr</code>属性</a>来使其布局在定义时就固定下来。在这两种情况下，字段在相应的结构体<em>表达式</em>中都可以以任何顺序给出；（但在相同的编译目标中，在）同一布局规则下生成的结构体(<code>struct</code>)值将始终具有相同的内存布局。</p>
<p>结构体(<code>struct</code>)的字段可以由<a href="types/../visibility-and-privacy.html">可见性修饰符(visibility modifiers)</a>限定，以允许从模块之外来访问结构体中的数据。</p>
<p>*元组结构体(uple struct)*类型与结构体类型类似，只是字段是匿名的。</p>
<p>*单元结构体(unit-like struct)*类型类似于结构体类型，只是它没有字段。由初始<a href="types/../expressions/struct-expr.html">结构体表达式</a>构造的值是驻留在此类类型中惟一的值。</p>
<div class="footnote-definition" id="structtype"><sup class="footnote-definition-label">1</sup>
<p><code>struct</code>类型类似于 C 中的 <code>struct</code> 类型、ML家族的 <em>record</em> 类型或 Lisp 家族的 <em>struct</em> 类型。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#enumerated-types" id="enumerated-types">Enumerated types</a></h1>
<h1><a class="header" href="#枚举类型" id="枚举类型">枚举类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/enum.md">enum.md</a><br />
commit: d8cbe4eedb77bae3db9eff87b1238e7e23f6ae92 <br />
本章译文最后维护日期：2021-2-21</p>
</blockquote>
<p><em>枚举类型</em>是一种标称型(nominal)的、异构的、不相交的类型联合起来组成的类型，它直接用<a href="types/../items/enumerations.html">枚举(<code>enum</code>)程序项</a>的名称来表示。<sup class="footnote-reference"><a href="#enumtype">1</a></sup></p>
<p><a href="types/../items/enumerations.html">枚举(<code>enum</code>)程序项</a>同时声明了类型和它的各种<em>变体(variants)</em>，其中每个变体都独立命名，可使用定义结构体、元组结构体或单元结构体(unit-like struct)的句法来定义它们。</p>
<p>枚举(<code>enum</code>)的实例可以通过<a href="types/../expressions/struct-expr.html">结构体体表达式</a>来构造。</p>
<p>任何枚举值消耗的内存和其同类型的其他变体都是相同的，具体都为其枚举(<code>enum</code>)类型的最大变体所需的内存再加上存储其判别值(discriminant)所需的内存。</p>
<p>枚举类型不能在<em>结构上</em>表示为类型，必须通过对<a href="types/../items/enumerations.html">枚举程序项</a>的具名引用(named reference)来表示。<sup class="footnote-reference"><a href="#译注1">2</a></sup></p>
<div class="footnote-definition" id="enumtype"><sup class="footnote-definition-label">1</sup>
<p><code>enum</code>类型类似于 ML 中的数据(<code>data</code>)构造函数声明，或 Limbo 中的 <em>pick ADT</em>。</p>
</div>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">2</sup>
<p>译者理解这句话的意思是：枚举不同于普通结构化的类型，所有的枚举类型都是对枚举程序项的引用；这里引用分两种，一种是类C枚举，就是对程序项的直接具名引用；另一种是带字段的枚举变体，这种其实是类似于 <code>Box</code>、<code>Rc</code> 这样的具名引用，它通过封装其他类型来指导数据的存储和限定其上可用的操作。</p>
</div>
<h1><a class="header" href="#union-types" id="union-types">Union types</a></h1>
<h1><a class="header" href="#联合体类型" id="联合体类型">联合体类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/union.md">union.md</a><br />
commit: cd996a4e6e9b98929c3718fd76988bfee51d757c <br />
本章译文最后维护日期：2020-12-24</p>
</blockquote>
<p><em>联合体类型</em>是一种标称型(nominal)的、异构的、类似C语言里的 union 的类型，具体的类型名称由<a href="types/../items/unions.html">联合体(<code>union</code>)程序项</a>的名称表示。</p>
<p>Since transmutes can cause unexpected or undefined behaviour, <code>unsafe</code> is required to read from a union field, or to write to a field that doesn't implement <a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a> or has a [<code>ManuallyDrop</code>] type. See the <a href="types/../items/unions.html">item</a> documentation for further details.
联合体没有“活跃字段(active field)”的概念。相反，每次对联合体的访问都将联合体的部分存储内容转换为被访问字段的类型。由于转换可能会导致意外或未定义行为，所以读取联合体字段，或写入未实现 <a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a> 或 [<code>ManuallyDrop</code>] 的联合体字段的操作都需要放在 <code>unsafe</code>块内进行。有关详细信息，请参阅相应的<a href="types/../items/unions.html">程序项</a>文档。</p>
<p>默认情况下，联合体(<code>union</code>)的内存布局是未定义的，但是可以使用 <code>#[repr(...)]</code>属性来固定为某一类型布局。</p>
<!-- 2020-12-24-->
<!-- checked -->
<h1><a class="header" href="#function-item-types" id="function-item-types">Function item types</a></h1>
<h1><a class="header" href="#函数项类型" id="函数项类型">函数项类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/function-item.md">function-item.md</a><br />
commit: b0e0ad6490d6517c19546b1023948986578fc378 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<p>当被引用函数项、元组结构体的构造函数或枚举变体的构造函数时，会产生它们的*函数项类型(function item type)*的零尺寸的值。这种类型（也就是此值）显式地标识了该函数——标识出的内容包括程序项定义时的名字、类型参数，及其定义时的生存期参数（不是后期绑定的生存期参数，后期绑定的生存期参数只在函数被调用时才被赋与）——所以该值不需要包含一个实际的函数指针，当此函数被调用时也不需要一个间接的寻址操作去查找此函数。</p>
<p>没有直接引用函数项类型的句法，但是编译器会在错误消息中会显示类似于 <code>fn(u32) -&gt; i32 {fn_name}</code> 这样的“类型”。</p>
<p>因为函数项类型显式地标识了其函数，所以如果它们所指的程序项不同（包括不同的程序项，或相同的程序项但泛型参数的实际类型不同），则此函数项类型也不同，混合使用它们将导致类型错误：</p>
<pre><pre class="playground"><code class="language-rust compile_fail E0308 edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn foo&lt;T&gt;() { }
let x = &amp;mut foo::&lt;i32&gt;;
*x = foo::&lt;u32&gt;; //~ 错误：类型不匹配
<span class="boring">}
</span></code></pre></pre>
<p>但确实存在从函数项类型到具有相同签名的函数指针的<a href="types/../type-coercions.html">自动强转(coercion)</a>，这种自动强转一般发生在使用函数项类型却直接预期函数指针时；另一种发生情况是 <code>if</code>表达式或匹配(<code>match</code>)表达式的不同分支返回使用了具有相同签名却使用了不同函数项类型的情况：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let want_i32 = false;
</span><span class="boring">fn foo&lt;T&gt;() { }
</span>
// 这里 `foo_ptr_1` 标注使用了 `fn()` 这个函数指针类型。
let foo_ptr_1: fn() = foo::&lt;i32&gt;;

// ... `foo_ptr_2` 也行 - 这次是通过类型检查(type-checks)做到的。
let foo_ptr_2 = if want_i32 {
    foo::&lt;i32&gt;
} else {
    foo::&lt;u32&gt;
};
<span class="boring">}
</span></code></pre></pre>
<p>所有的函数项类型都实现了 <a href="https://doc.rust-lang.org/std/ops/trait.Fn.html"><code>Fn</code></a>、<a href="https://doc.rust-lang.org/std/ops/trait.FnMut.html"><code>FnMut</code></a>、<a href="https://doc.rust-lang.org/std/ops/trait.FnOnce.html"><code>FnOnce</code></a>、<a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a>、<a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a>、<a href="types/../special-types-and-traits.html#send"><code>Send</code></a> 和 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a>。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#closure-types" id="closure-types">Closure types</a></h1>
<h1><a class="header" href="#闭包类型" id="闭包类型">闭包类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/closure.md">closure.md</a><br />
commit: 9f106217c7598d0ec7b39e936d88f843a5d5175f <br />
本章译文最后维护日期：2021-07-11</p>
</blockquote>
<p><a href="types/../expressions/closure-expr.html">闭包表达式</a>生成的闭包值具有唯一性和无法写出的匿名性。闭包类型近似相当于包含捕获变量的结构体。比如以下闭包示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn f&lt;F : FnOnce() -&gt; String&gt; (g: F) {
    println!(&quot;{}&quot;, g());
}

let mut s = String::from(&quot;foo&quot;);
let t = String::from(&quot;bar&quot;);

f(|| {
    s += &amp;t;
    s
});
// 打印 &quot;foobar&quot;.
<span class="boring">}
</span></code></pre></pre>
<p>生成大致如下所示的闭包类型：</p>
<!-- ignore: simplified, requires unboxed_closures, fn_traits -->
<pre><code class="language-rust ignore">struct Closure&lt;'a&gt; {
    s : String,
    t : &amp;'a String,
}

impl&lt;'a&gt; FnOnce&lt;()&gt; for Closure&lt;'a&gt; {
    type Output = String;
    fn call_once(self) -&gt; String {
        self.s += &amp;*self.t;
        self.s
    }
}
</code></pre>
<p>所以调用 <code>f</code> 相当于：</p>
<!-- ignore: continuation of above -->
<pre><code class="language-rust ignore">f(Closure{s: s, t: &amp;t});
</code></pre>
<h2><a class="header" href="#capture-modes-1" id="capture-modes-1">Capture modes</a></h2>
<h2><a class="header" href="#捕获方式-1" id="捕获方式-1">捕获方式</a></h2>
<p>编译器倾向于优先通过不可变借用(immutable borrow)来捕获闭合变量(closed-over variable)，其次是通过唯一不可变借用(unique immutable borrow)（见下文），再其次可变借用(mutable borrow)，最后使用移动语义(move)来捕获。编译器将选择与捕获的变量在闭包体中的使用方式兼容的第一种捕获方式。编译器不会考虑周围的代码，比如所涉及的变量的生存期，或者闭包本身的生存期。</p>
<p>如果使用了关键字 <code>move</code> ，那么所有捕获都是通过移动(move)语义进行的（当然对于 <code>Copy</code>类型，则是通过拷贝语义进行的），而不管借用是否可用。关键字 <code>move</code> 通常用于允许闭包比其捕获的值活得更久，例如返回闭包或用于生成新线程。</p>
<p>复合类型（如结构体、元组和枚举）始终是全部捕获的，而不是各个字段分开捕获的。如果真要捕获单个字段，那可能需要先借用该字段到本地局部变量中：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">use std::collections::HashSet;
</span><span class="boring">
</span>struct SetVec {
    set: HashSet&lt;u32&gt;,
    vec: Vec&lt;u32&gt;
}

impl SetVec {
    fn populate(&amp;mut self) {
        let vec = &amp;mut self.vec;
        self.set.iter().for_each(|&amp;n| {
            vec.push(n);
        })
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>相反，如果闭包直接使用了 <code>self.vec</code>，那么它将尝试通过可变引用捕获 <code>self</code>。但是因为 <code>self.set</code> 已经被借出用来迭代了，所以代码将无法编译。</p>
<h2><a class="header" href="#unique-immutable-borrows-in-captures" id="unique-immutable-borrows-in-captures">Unique immutable borrows in captures</a></h2>
<h2><a class="header" href="#捕获中的唯一不可变借用" id="捕获中的唯一不可变借用">捕获中的唯一不可变借用</a></h2>
<p>捕获方式中有一种被称为<em>唯一不可变借用</em>的特殊类型的借用捕获，这种借用不能在语言的其他任何地方使用，也不能显式地写出。唯一不可变借用发生在修改可变引用的引用对象(referent)时，如下面的示例所示：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let mut b = false;
let x = &amp;mut b;
{
    let mut c = || { *x = true; };
    // 下行代码不正确
    // let y = &amp;x;
    c();
}
let z = &amp;x;
<span class="boring">}
</span></code></pre></pre>
<p>在这种情况下，不能去可变借用 <code>x</code>，因为 <code>x</code> 没有标注 <code>mut</code>。但与此同时，如果不可变借用 <code>x</code>，那对其赋值又会非法，因为 <code>&amp; &amp;mut</code> 引用可能不是唯一的，因此此引用不能安全地用于修改值。所以这里闭包使用了唯一不可变借用：它采用了不可变的方式借用了 <code>x</code>，但是又像可变借用一样，当然前提是此借用必须是唯一的。在上面的例子中，解开 <code>y</code> 那行上的注释将产生错误，因为这将违反闭包对 <code>x</code> 的借用的唯一性；<code>z</code> 的声明是有效的，因为闭包的生存期在块结束时已过期，从而已经释放了对 <code>x</code> 的借用。</p>
<h2><a class="header" href="#call-traits-and-coercions" id="call-traits-and-coercions">Call traits and coercions</a></h2>
<h2><a class="header" href="#调用trait-和自动强转" id="调用trait-和自动强转">调用trait 和自动强转</a></h2>
<p>闭包类型都实现了 <a href="https://doc.rust-lang.org/std/ops/trait.FnOnce.html"><code>FnOnce</code></a>，这表明它们可以通过消耗掉闭包的所有权来调用执行它一次。此外，一些闭包实现了更具体的调用trait：</p>
<ul>
<li>
<p>对没采用移动语义来捕获任何变量（译者注：变量的原始所有者仍拥有该变量的所有权）的闭包都实现了 <a href="https://doc.rust-lang.org/std/ops/trait.FnMut.html"><code>FnMut</code></a>，这表明该闭包可以通过可变引用来调用。</p>
</li>
<li>
<p>对捕获的变量没移出其值，也没去修改其值的闭包都实现了 <a href="https://doc.rust-lang.org/std/ops/trait.Fn.html"><code>Fn</code></a>，这表明该闭包可以通过共享引用来调用。</p>
</li>
</ul>
<blockquote>
<p>注意：<code>move</code>闭包可能仍然实现 <a href="https://doc.rust-lang.org/std/ops/trait.Fn.html"><code>Fn</code></a> 或 <a href="https://doc.rust-lang.org/std/ops/trait.FnMut.html"><code>FnMut</code></a>，即使它们通过移动(move)语义来捕获变量。这是因为闭包类型实现什么样的 trait 是由闭包对捕获的变量值做了什么来决定的，而不是由闭包如何捕获它们来决定的。<sup class="footnote-reference"><a href="#译注1">1</a></sup></p>
</blockquote>
<p>*非捕获闭包(Non-capturing closures)*是指不捕获环境中的任何变量的闭包。它们可以通过匹配签名的方式被自动强转成函数指针（例如 <code>fn()</code>）。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let add = |x, y| x + y;

let mut x = add(5,7);

type Binop = fn(i32, i32) -&gt; i32;
let bo: Binop = add;
x = bo(5,7);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#other-traits" id="other-traits">Other traits</a></h2>
<h2><a class="header" href="#其他-trait" id="其他-trait">其他 trait</a></h2>
<p>所有闭包类型都实现了 <a href="types/../special-types-and-traits.html#sized"><code>Sized</code></a>。此外，闭包捕获的变量的类型如果实现了如下 trait，此闭包类型也会自动实现这些 trait：</p>
<ul>
<li><a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a></li>
<li><a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a></li>
<li><a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a></li>
<li><a href="types/../special-types-and-traits.html#send"><code>Send</code></a></li>
</ul>
<p>闭包类型实现 <a href="types/../special-types-and-traits.html#send"><code>Send</code></a> 和 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a> 的规则与普通结构体类型实现这俩 trait 的规则一样，而 <a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a> 和 <a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a> 就像它们在 <a href="types/../attributes/derive.html"><code>derived</code></a>属性中表现的一样。对于 <a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a>，捕获变量的克隆顺序目前还没正式的规范出来。</p>
<p>由于捕获通常是通过引用进行的，因此会出现以下一般规则：</p>
<ul>
<li>如果所有的捕获变量都实现了 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a>，则此闭包就也实现了 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a> 。</li>
<li>如果所有非唯一不可变引用捕获的变量都实现了 <a href="types/../special-types-and-traits.html#sync"><code>Sync</code></a>，并且所有由唯一不可变、可变引用、复制或移动语义捕获的值都实现了 <a href="types/../special-types-and-traits.html#send"><code>Send</code></a>，则此闭包就也实现了 <a href="types/../special-types-and-traits.html#send"><code>Send</code></a>。</li>
<li>如果一个闭包没有通过唯一不可变引用或可变引用捕获任何值，并且它通过复制或移动语义捕获的所有值都分别实现了 <a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a> 或 <a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a>，则此闭包就也实现了 <a href="types/../special-types-and-traits.html#clone"><code>Clone</code></a> 或 <a href="types/../special-types-and-traits.html#copy"><code>Copy</code></a>。</li>
</ul>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>译者的实验代码：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn f1&lt;F : Fn() -&gt; i32&gt; (g: F) { println!(&quot;{}&quot;, g());}
fn f2&lt;F : FnMut() -&gt; i32&gt; (mut g: F) { println!(&quot;{}&quot;, g());}
let t = 8;    
f1(move || { t });
f2(move || { t });
<span class="boring">}
</span></code></pre></pre>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#pointer-types" id="pointer-types">Pointer types</a></h1>
<h1><a class="header" href="#指针类型" id="指针类型">指针类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/pointer.md">pointer.md</a><br />
commit: 4664361ba2f7bcc568f6bef4d119b53971fdf8ad <br />
本章译文最后维护日期：2021-4-6</p>
</blockquote>
<p>Rust 中所有的指针都是显式的头等(first-class)值。
它们可以被移动或复制，存储到其他数据结构中，或从函数中返回。</p>
<h2><a class="header" href="#references--and-mut" id="references--and-mut">References (<code>&amp;</code> and <code>&amp;mut</code>)</a></h2>
<h2><a class="header" href="#引用-和-mut" id="引用-和-mut">引用(<code>&amp;</code> 和 <code>&amp;mut</code>)</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ReferenceType</em> :<br />
   <code>&amp;</code> <a href="types/../trait-bounds.html"><em>Lifetime</em></a><sup>?</sup> <code>mut</code><sup>?</sup> <a href="types/../types.html#type-expressions"><em>TypeNoBounds</em></a></p>
</blockquote>
<h3><a class="header" href="#shared-references-" id="shared-references-">Shared references (<code>&amp;</code>)</a></h3>
<h3><a class="header" href="#共享引用" id="共享引用">共享引用(<code>&amp;</code>)</a></h3>
<p>共享引用(<code>&amp;</code>)指向<em>由其他值拥有的</em>内存。
创建了对值的共享引用可以防止对该值的直接更改。
但在某些特定情况下，<a href="types/../interior-mutability.html">内部可变性</a>又提供了这种情况的一种例外。
顾名思义，对一个值的共享引用的次数没有限制。共享引用类型被写为 <code>&amp;type</code>；当需要指定显式的生存期时可写为 <code>&amp;'a type</code>。
拷贝一个引用是一个“浅拷贝(shallow)”操作：它只涉及复制指针本身，也就是指针实现了 <code>Copy</code> trait 的意义所在。
释放引用对共享引用所指向的值没有影响，但是对<a href="types/../expressions.html#temporaries">临时值</a>的引用的存在将使此临时值在此引用的作用域内保持存活状态。</p>
<h3><a class="header" href="#mutable-references-mut" id="mutable-references-mut">Mutable references (<code>&amp;mut</code>)</a></h3>
<h3><a class="header" href="#可变引用mut" id="可变引用mut">可变引用(<code>&amp;mut</code>)</a></h3>
<p>可变引用(<code>&amp;mut</code>)也指向其他值所拥有的内存。
可变引用类型被写为 <code>&amp;mut type</code> 或 <code>&amp;'a mut type</code>。
可变引用（其还未被借出<sup class="footnote-reference"><a href="#译注1">1</a></sup>）是访问它所指向的值的唯一方法，所以可变引用没有实现 <code>Copy</code> trait。</p>
<h2><a class="header" href="#raw-pointers-const-and-mut" id="raw-pointers-const-and-mut">Raw pointers (<code>*const</code> and <code>*mut</code>)</a></h2>
<h2><a class="header" href="#裸指针const-和-mut" id="裸指针const-和-mut">裸指针(<code>*const</code> 和 <code>*mut</code>)</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>RawPointerType</em> :<br />
   <code>*</code> ( <code>mut</code> | <code>const</code> ) <a href="types/../types.html#type-expressions"><em>TypeNoBounds</em></a></p>
</blockquote>
<p>裸指针是没有安全性或可用性(liveness)保证的指针。
裸指针写为 <code>*const T</code> 或 <code>*mut T</code>，例如，<code>*const i32</code> 表示指向 32-bit 有符号整数的裸指针。
拷贝或销毁(dropping )裸指针对任何其他值的生命周期(lifecycle)都没有影响。对
裸指针的解引用是<a href="types/../unsafety.html">非安全(<code>unsafe</code>)操作</a>，可以通过重新借用裸指针（<code>&amp;*</code> 或 <code>&amp;mut *</code>）将其转换为引用。
在 Rust 代码中通常不鼓励使用裸指针；它们的存在是为了提升与外部代码的互操作性，以及编写对性能要求很高的函数或很底层的函数。</p>
<p>在比较裸指针时，比较的是它们的地址，而不是它们指向的数据。
当比较裸指针和<a href="types/../dynamically-sized-types.html">动态尺寸类型</a>时，还会比较它们指针上的附加/元数据。</p>
<p>可以直接使用 <a href="types/../../core/ptr/macro.addr_of.html"><code>core::ptr::addr_of!</code></a> 创建 <code>*const</code> 类型的裸指针，通过 <a href="types/../../core/ptr/macro.addr_of_mut.html"><code>core::ptr::addr_of_mut!</code></a> 创建 <code>*mut</code> 类型的裸指针。</p>
<h2><a class="header" href="#smart-pointers" id="smart-pointers">Smart Pointers</a></h2>
<h2><a class="header" href="#智能指针" id="智能指针">智能指针</a></h2>
<p>标准库包含了一些额外的“智能指针”类型，它们提供了在引用和裸指针这类低级指针之外的更多的功能。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>译者理解这里是指 <code>&amp;mut type</code> 如果被借出，就成了 <code>&amp;&amp;mut type</code>，这样就又成了不可变借用了。</p>
</div>
<h1><a class="header" href="#function-pointer-types" id="function-pointer-types">Function pointer types</a></h1>
<h1><a class="header" href="#函数指针类型" id="函数指针类型">函数指针类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/function-pointer.md">function-pointer.md</a><br />
commit: 33784fadb81c16918c7e6d207f8c838232c159b0 <br />
本章译文最后维护日期：2021-5-29</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>BareFunctionType</em> :<br />
   <a href="types/../trait-bounds.html#higher-ranked-trait-bounds"><em>ForLifetimes</em></a><sup>?</sup> <em>FunctionTypeQualifiers</em> <code>fn</code><br />
       <code>(</code> <em>FunctionParametersMaybeNamedVariadic</em><sup>?</sup> <code>)</code> <em>BareFunctionReturnType</em><sup>?</sup></p>
<p><em>FunctionTypeQualifiers</em>:<br />
   <code>unsafe</code><sup>?</sup> (<code>extern</code> <a href="types/../items/functions.html"><em>Abi</em></a><sup>?</sup>)<sup>?</sup></p>
<p><em>BareFunctionReturnType</em>:<br />
   <code>-&gt;</code> <a href="types/../types.html#type-expressions"><em>TypeNoBounds</em></a></p>
<p><em>FunctionParametersMaybeNamedVariadic</em> :<br />
   <em>MaybeNamedFunctionParameters</em> | <em>MaybeNamedFunctionParametersVariadic</em></p>
<p><em>MaybeNamedFunctionParameters</em> :<br />
   <em>MaybeNamedParam</em> ( <code>,</code> <em>MaybeNamedParam</em> )<sup>*</sup> <code>,</code><sup>?</sup></p>
<p><em>MaybeNamedParam</em> :<br />
   <a href="types/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> ( ( <a href="types/../identifiers.html">IDENTIFIER</a> | <code>_</code> ) <code>:</code> )<sup>?</sup> <a href="types/../types.html#type-expressions"><em>Type</em></a></p>
<p><em>MaybeNamedFunctionParametersVariadic</em> :<br />
   ( <em>MaybeNamedParam</em> <code>,</code> )<sup>*</sup> <em>MaybeNamedParam</em> <code>,</code> <a href="types/../attributes.html"><em>OuterAttribute</em></a><sup>*</sup> <code>...</code></p>
</blockquote>
<p>函数指针类型（使用关键字 <code>fn</code> 写出）指向那些在编译时不必知道函数标识符的函数。它们也可以由<a href="types/function-item.html">函数项</a>类型或非捕获(non-capturing)<a href="types/closure.html">闭包</a>经过一次自动强转(coercion)来创建。</p>
<p>非安全(<code>unsafe</code>)限定符表示类型的值是一个<a href="types/../unsafe-functions.html">非安全函数</a>，而外部(<code>extern</code>)限定符表示它是一个<a href="types/../items/functions.html#extern-function-qualifier">外部函数</a>。</p>
<p>可变参数只能通过使用 <code>&quot;C&quot;</code> 或 <code>&quot;cdecl&quot;</code> 的 ABI调用约定的 <a href="types/../items/external-blocks.html"><code>extern</code></a>函数类型来指定。</p>
<p>下面示例中 <code>Binop</code> 被定义为函数指针类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn add(x: i32, y: i32) -&gt; i32 {
    x + y
}

let mut x = add(5,7);

type Binop = fn(i32, i32) -&gt; i32;
let bo: Binop = add;
x = bo(5,7);
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#attributes-on-function-pointer-parameters" id="attributes-on-function-pointer-parameters">Attributes on function pointer parameters</a></h2>
<h2><a class="header" href="#函数指针参数上的属性" id="函数指针参数上的属性">函数指针参数上的属性</a></h2>
<p>函数指针参数上的属性遵循与<a href="types/../items/functions.html#attributes-on-function-parameters">常规函数参数</a>相同的规则和限制。</p>
<!-- 2021-1-17-->
<!-- checked -->
<h1><a class="header" href="#trait-objects" id="trait-objects">Trait objects</a></h1>
<h1><a class="header" href="#trait对象" id="trait对象">trait对象</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/trait-object.md">trait-object.md</a><br />
commit: fd10e7043934711ef96b4dd2009db3e4d0182a33 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TraitObjectType</em> :<br />
   <code>dyn</code><sup>?</sup> <a href="types/../trait-bounds.html"><em>TypeParamBounds</em></a></p>
<p><em>TraitObjectTypeOneBound</em> :<br />
   <code>dyn</code><sup>?</sup> <a href="types/../trait-bounds.html"><em>TraitBound</em></a></p>
</blockquote>
<p>*trait对象<sup class="footnote-reference"><a href="#译注1">1</a></sup>*是另一种类型的不透明值(opaque value)，它实现了一组 trait。<sup class="footnote-reference"><a href="#译注2">2</a></sup> 这组 trait 是由一个<a href="types/../items/traits.html#object-safety">对象安全的</a><em>基础trait(base trait)</em> 加上任意数量的<a href="types/../special-types-and-traits.html#auto-traits">自动trait(auto traits)</a>组成。</p>
<p>trait对象实现了基础trait、它的自动trait 以及其基础trait 的任何<a href="types/../items/traits.html#supertraits">超类trait(supertraits)</a>。</p>
<p>trait对象被写为为可选的关键字 <code>dyn</code> 后跟一组 trait约束，这些 trait约束有如此限制：除了第一个 trait 外，其他所有 trait 都必须是自动trait；生存期不能超过一个；不允许选择退出约束(opt-out bounds)（例如 <code>?Sized</code>）。此外，trait 的路径可以用圆括号括起来。</p>
<p>例如，给定一个trait <code>Trait</code>，下面所有的形式都是 trait对象：</p>
<ul>
<li><code>Trait</code></li>
<li><code>dyn Trait</code></li>
<li><code>dyn Trait + Send</code></li>
<li><code>dyn Trait + Send + Sync</code></li>
<li><code>dyn Trait + 'static</code></li>
<li><code>dyn Trait + Send + 'static</code></li>
<li><code>dyn Trait +</code></li>
<li><code>dyn 'static + Trait</code>.</li>
<li><code>dyn (Trait)</code></li>
</ul>
<blockquote>
<p><strong>版本差异</strong>：在 2015 版里，如果 trait对象的第一个约束是以 <code>::</code> 开头的路径，那么 <code>dyn</code> 会被视为路径的一部分。可以把第一条路径放在圆括号中来绕过这个问题。因此，如果希望 trait对象具有 <code>::your_module::Trait</code> 路径，那么应该将其写为  <code>dyn (::your_module::Trait)</code>。</p>
<p>从2018版本开始，<code>dyn</code> 是一个真正的关键字了，不允许在路径中使用，（不存在二义性了，）因此括号就没必要了。</p>
<p>注意：为了清晰起见，建议总是在 trait对象上使用关键字 <code>dyn</code>，除非你的代码库支持用Rust 1.26 或更低的版本来编译。</p>
</blockquote>
<p>如果基础trait 互为别名，并且自动trait 相同，生存期约束也相同，则这两种 trait对象类型互为别名。例如，<code>dyn Trait + Send + UnwindSafe</code> 和 <code>dyn Trait + UnwindSafe + Send</code> 是等价的。</p>
<p>由于值的具体类型是不透明的，trait对象是<a href="types/../dynamically-sized-types.html">动态尺寸类型</a>。像所有的 <abbr title="dynamically sized types">DST</abbr> 一样，trait对象常被用在某种类型的指针后面；例如 <code>&amp;dyn SomeTrait</code> 或 <code>Box&lt;dyn SomeTrait&gt;</code>。每个指向 trait对象的指针实例包括：</p>
<ul>
<li>一个指向实现 <code>SomeTrait</code> 的（那个真实的不透明的）类型 <code>T</code> 的实例的指针</li>
<li>一个指向*虚拟方法表(virtual method table_)*的指针。虚拟方法表也通常被称为 <em>虚函数表(vtable)</em>，它包含了 <code>T</code> 实现的 <code>SomeTrait</code> 的所有方法，<code>T</code> 实现的 <code>SomeTrait</code> 的<a href="types/../items/traits.html#supertraits">超类trait</a> 的每个方法，还有指向 <code>T</code> 的实现的指针（即函数指针）。</li>
</ul>
<p>trait对象的目的是允许方法的“延迟绑定(late binding)”。在 trait对象上调用一个方法会导致运行时的虚拟分发(virtual dispatch)：也就是说，一个函数指针从 trait对象的虚函数表(vtable)中被加载进来，并被间接调用。每个虚函数表实体的实际实现可能因对象的不同而不同。</p>
<p>一个 trait对象的例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">trait Printable {
    fn stringify(&amp;self) -&gt; String;
}

impl Printable for i32 {
    fn stringify(&amp;self) -&gt; String { self.to_string() }
}

fn print(a: Box&lt;dyn Printable&gt;) {
    println!(&quot;{}&quot;, a.stringify());
}

fn main() {
    print(Box::new(10) as Box&lt;dyn Printable&gt;);
}
</code></pre></pre>
<p>在本例中，trait <code>Printable</code> 作为 trait对象出现在 以 <code>print</code> 为类型签名的函数的参数中 和 <code>main</code> 中的类型转换表达式(cast expression)中。</p>
<h2><a class="header" href="#trait-object-lifetime-bounds" id="trait-object-lifetime-bounds">Trait Object Lifetime Bounds</a></h2>
<h2><a class="header" href="#trait对象的生存期约束" id="trait对象的生存期约束">trait对象的生存期约束</a></h2>
<p>因为 trait对象可以包含引用，所以这些引用的生存期需要表示为 trait对象的一部分。这种生存期被写为 <code>Trait + 'a</code>。<a href="types/../lifetime-elision.html#default-trait-object-lifetimes">默认情况</a>下，可以通过合理的选择来推断此生存期。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>本书行文中，使用“trait对象”这个词时，没区分 trait对象的值和类型本身，但一般都指类型。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">2</sup>
<p>译者认为这样翻译可能更容易理解：<em>trait对象</em>是丢失了/隐藏了具体真实类型的 trait实现的类型，此类型本身一般会实现了一组 trait。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#impl-trait" id="impl-trait">Impl trait</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/impl-object.md">impl-object.md</a><br />
commit: 94085bbf726d53f3c7ace1ce122c82ab7b691d39 <br />
本章译文最后维护日期：2020-5-29</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>ImplTraitType</em> : <code>impl</code> <a href="types/../trait-bounds.html"><em>TypeParamBounds</em></a></p>
<p><em>ImplTraitTypeOneBound</em> : <code>impl</code> <a href="types/../trait-bounds.html"><em>TraitBound</em></a></p>
</blockquote>
<p><code>impl Trait</code> 提供了指定实现某trait 的具体的但匿名的类型的方法。
它可以出现在两种位置上：参数位置（在这里它可以充当函数的匿名类型参数）和返回位置（在这里它可以充当抽象返回类型）。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait Trait {}
<span class="boring">impl Trait for () {}
</span>
// 参数位置：匿名类型参数
fn foo(arg: impl Trait) {
}

// 返回位置：抽象返回类型
fn bar() -&gt; impl Trait {
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#anonymous-type-parameters" id="anonymous-type-parameters">Anonymous type parameters</a></h2>
<h2><a class="header" href="#匿名类型参数" id="匿名类型参数">匿名类型参数</a></h2>
<blockquote>
<p>注意：匿名类型参数通常被称为“参数位置上的 trait约束(impl Trait in argument position)”。
(术语“参数”在这里更正式和正确，但 “impl Trait in argument position” 是在开发该特性时就使用的措辞，所以它仍保留在部分实现中。)</p>
</blockquote>
<p>函数可以使用 <code>impl</code> 后跟一组 trait约束，将参数声明为具有某匿名类型。
调用者必须提供一个满足匿名类型参数声明的约束的类型，并且在函数内只能使用该匿名参数类型的 trait约束内部声明的方法。</p>
<p>例如，下面两种形式几乎等价：</p>
<pre><code class="language-rust ignore">trait Trait {}

// 泛型类型参数
fn foo&lt;T: Trait&gt;(arg: T) {
}

// 参数位置上的trait
fn foo(arg: impl Trait) {
}
</code></pre>
<p>也就是说，参数位置上的 <code>impl Trait</code> 是泛型类型参数（如 <code>&lt;T: Trait&gt;</code>）的语法糖，只是该类型是匿名的，并且不出现在 <a href="types/../items/generics.html"><em>GenericParams</em></a> 列表中。</p>
<blockquote>
<p><strong>注意：</strong>
对于函数参数，泛型类型参数和 <code>impl Trait</code> 并不完全等价。
使用诸如 <code>&lt;T:Trait&gt;</code> 之类的泛型参数，调用者可以在调用点使用 <a href="types/../paths.html#paths-in-expressions"><em>GenericArgs</em></a>（例如，<code>foo:：&lt;usize&gt;（1）</code>）形式来显式指定 <code>T</code> 的泛型参数。
如果 <code>impl Trait</code> 是<em>任意</em>函数参数的类型，则调用者在调用该函数时不能提供任何泛型参数。这同样适用于返回类型或任何常量泛型的泛型参数。</p>
<p>因此，这样将函数签名从一个变更为另一个，对函数的调用者来说仍可能是一种破坏性的变更。</p>
</blockquote>
<h2><a class="header" href="#abstract-return-types" id="abstract-return-types">Abstract return types</a></h2>
<h2><a class="header" href="#抽象返回类型" id="抽象返回类型">抽象返回类型</a></h2>
<blockquote>
<p>注意： 这通常被称为“返回位置上的 Trait约束”(impl Trait in return position)。</p>
</blockquote>
<p>函数可以使用 <code>impl Trait</code> 返回抽象返回类型。
这些类型代表另一个具体类型，调用者只能使用指定的 <code>Trait</code> 内声明的方法。
函数的每个可能的返回分支返回的返回值都必须解析为相同的具体类型。</p>
<p>返回位置上的 <code>impl Trait</code> 允许函数返回非box化的抽象类型。
这对于<a href="types/closure.html">闭包</a>和迭代器特别有用。
例如，闭包具有唯一的、不可写的类型。
以前，从函数返回闭包的唯一方法是使用<a href="types/trait-object.html">trait对象</a>：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn returns_closure() -&gt; Box&lt;dyn Fn(i32) -&gt; i32&gt; {
    Box::new(|x| x + 1)
}
<span class="boring">}
</span></code></pre></pre>
<p>这不得不承受因堆分配和动态调度而带来的性能损失。
并且者无法完全指定闭包的类型，只能使用 <code>Fn</code> trait。
这意味着此时 trait对象是必要的。
但是，使用 <code>impl Trait</code>，可以像如下这样来更简单地编写代码：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn returns_closure() -&gt; impl Fn(i32) -&gt; i32 {
    |x| x + 1
}
<span class="boring">}
</span></code></pre></pre>
<p>这也避免了使用 box化的 trait对象的缺陷。</p>
<p>类似地，在迭代器的使用坏境中，如果将此步操作前的所有迭代器操作合并到一个执行链中，迭代器里的具体类型可能变得非常复杂。此时返回 <code>impl Iterator</code> 意味着一个函数只需将 <code>Iterator</code> trait 作为其返回类型的约束来公开，而不须显式指定链内所有其他涉及的迭代器类型。</p>
<h3><a class="header" href="#differences-between-generics-and-impl-trait-in-return-position" id="differences-between-generics-and-impl-trait-in-return-position">Differences between generics and <code>impl Trait</code> in return position</a></h3>
<h3><a class="header" href="#泛型与-impl-trait-在返回位置上的差异" id="泛型与-impl-trait-在返回位置上的差异">泛型与 <code>impl Trait</code> 在返回位置上的差异</a></h3>
<p>在参数位置，<code>impl Trait</code> 在语义上与泛型类型参数非常相似。
然而，两者在返回位置上存在显著差异。
与泛型类型参数不同，使用 <code>impl Trait</code> 时，函数选择返回类型，调用者不能选择返回类型。</p>
<p>泛型函数：</p>
<pre><code class="language-rust ignore">fn foo&lt;T: Trait&gt;() -&gt; T {
</code></pre>
<p>允许调用者来指定返回类型<code>T</code>，然后函数返回该类型。</p>
<p><code>impl Trait</code> 函数：</p>
<pre><code class="language-rust ignore">fn foo() -&gt; impl Trait {
</code></pre>
<p>不允许调用者指定返回类型。
相反，函数自身选择返回类型，但只承诺返回类型将实现 <code>Trait</code>。</p>
<h2><a class="header" href="#limitations-1" id="limitations-1">Limitations</a></h2>
<h2><a class="header" href="#限制-1" id="限制-1">限制</a></h2>
<p><code>impl Trait</code> 只能作为自由函数或固有函数的参数或返回类型出现。
它不能出现在 trait实现中，也不能出现在 let绑定的类型或出现在类型别名中。</p>
<h1><a class="header" href="#type-parameters" id="type-parameters">Type parameters</a></h1>
<h1><a class="header" href="#类型参数" id="类型参数">类型参数</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/parameters.md">parameters.md</a><br />
commit: eb02dd5194a747277bfa46b0185d1f5c248f177b <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<p>在带有类型参数声明的程序项的代码体内，这些类型参数的名称可以直接当做类型使用：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn to_vec&lt;A: Clone&gt;(xs: &amp;[A]) -&gt; Vec&lt;A&gt; {
    if xs.is_empty() {
        return vec![];
    }
    let first: A = xs[0].clone();
    let mut rest: Vec&lt;A&gt; = to_vec(&amp;xs[1..]);
    rest.insert(0, first);
    rest
}
<span class="boring">}
</span></code></pre></pre>
<p>这里，<code>first</code> 的类型为 <code>A</code>，援引的是 <code>to_vec</code> 的类型参数 <code>A</code>；<code>rest</code> 的类型为 <code>Vec&lt;A&gt;</code>，它是一个元素类型为 <code>A</code> 向量(vector)。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#inferred-type" id="inferred-type">Inferred type</a></h1>
<h1><a class="header" href="#自动推断型类型" id="自动推断型类型">自动推断型类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/types/parameters.md">parameters.md</a><br />
commit: 43dc1a42f19026f580e34a095e91804c3d6da186 <br />
本章译文最后维护日期：2020-11-14</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>InferredType</em> : <code>_</code></p>
</blockquote>
<p>自动推断型类型要求编译器尽可能根据周围可用的信息推断出实际使用类型。它不能用于程序项的签名中。它经常用于泛型参数中：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x: Vec&lt;_&gt; = (0..10).collect();
<span class="boring">}
</span></code></pre></pre>
<!--
  这里还有什么要说的？
  我所知道的唯一文档是https://rustc-dev-guide.rust-lang.org/type-inference.html
  有关类型推断应该需要进一步的广泛讨论。
-->
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#dynamically-sized-types" id="dynamically-sized-types">Dynamically Sized Types</a></h1>
<h1><a class="header" href="#动态尺寸类型" id="动态尺寸类型">动态尺寸类型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/dynamically-sized-types.md">dynamically-sized-types.md</a><br />
commit: 4e138b37b49c49bc875b96b859fbe0caea5a82f3 <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<p>大多数的类型都有一个在编译时就已知的固定尺寸，并实现了 trait <a href="special-types-and-traits.html#sized"><code>Sized</code></a>。只有在运行时才知道尺寸的类型称为<em>动态尺寸类型(dynamically sized type)</em>（<em>DST</em>），或者非正式地称为非固定尺寸类型(unsized type)。<a href="types/slice.html">切片</a>和 <a href="types/trait-object.html">trait对象</a>是 <abbr title="dynamically sized types">DSTs</abbr> 的两个例子。此类类型只能在某些情况下使用:</p>
<ul>
<li>指向 <abbr title="dynamically sized types">DST</abbr> 的<a href="types/pointer.html">指针类型</a>的尺寸是固定的(sized)，但是是指向固定尺寸类型的指针的尺寸的两倍
<ul>
<li>指向切片的指针也存储了切片的元素的数量。</li>
<li>指向 trait对象的指针也存储了一个指向虚函数表(vtable)的指针地址</li>
</ul>
</li>
<li><abbr title="dynamically sized types">DST</abbr> 可以作为类型实参( type arguments)来传给有 <code>?Sized</code>约束的泛型参数。
当关联类型的声明有 <code>？size</code>约束时，它们也可以被用于关联类型定义。
默认情况下，任何类型参数或关联类型都有 <code>Sized</code>约束，除非它们使用了 <code>Sized</code>来放宽其约束。</li>
<li>可以为 <abbr title="dynamically sized types">DSTs</abbr> 实现 trait。
与泛型类型参数中的默认设置不同，在 trait定义中，<code>Self: ?Sized</code>约束是默认情况。</li>
<li>结构体可以包含一个 <abbr title="dynamically sized type">DST</abbr> 作为最后一个字段，这使得该结构体也成为是一个 <abbr title="dynamically sized type">DST</abbr>。</li>
</ul>
<blockquote>
<p><strong>注意</strong>：<a href="variables.html">变量</a>、函数参数、<a href="items/constant-items.html">常量</a>项和<a href="items/static-items.html">静态</a>项必须是 <code>Sized</code>。</p>
</blockquote>
<h1><a class="header" href="#type-layout" id="type-layout">Type Layout</a></h1>
<h1><a class="header" href="#类型布局" id="类型布局">类型布局</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/type-layout.md">type-layout.md</a><br />
commit: 0cb7e46722353a5de852d03684b4895516f92a4d <br />
本章译文最后维护日期：2021-06-27</p>
</blockquote>
<p>类型的布局描述类型的尺寸(size)、对齐量(alignment)和字段(fields)的<em>相对偏移量(relative offsets)</em>。对于枚举，其判别值(discriminant)的布局和解释也是类型布局的一部分。</p>
<p>每次编译都有可能更改类型布局。这里我们只阐述当前编译器所保证的内容，而没试图去阐述编译器对此做了什么。</p>
<h2><a class="header" href="#size-and-alignment" id="size-and-alignment">Size and Alignment</a></h2>
<h2><a class="header" href="#尺寸和对齐量" id="尺寸和对齐量">尺寸和对齐量</a></h2>
<p>所有值都有对一个齐量和尺寸。</p>
<p>值的<em>对齐量</em>指定了哪些地址可以有效地存储该值。对齐量为 <code>n</code> 的值只能存储地址为 n 的倍数的内存地址上。例如，对齐量为 2 的值必须存储在偶数地址上，而对齐量为 1 的值可以存储在任何地址上。对齐量是用字节数来度量的，必须至少是 1，并且总是 2 的幂次。值的对齐量可以通过函数 <a href="https://doc.rust-lang.org/std/mem/fn.align_of_val.html"><code>align_of_val</code></a> 来检测。</p>
<p>值的<em>尺寸</em>是同类型的值组成的数组中连续两个元素之间的字节偏移量，此偏移量包括了为保持程序项类型内部对齐而对此类型做的对齐填充。值的尺寸总是其对齐量的非负整数倍数。值的尺寸可以通过函数 <a href="https://doc.rust-lang.org/std/mem/fn.size_of_val.html"><code>size_of_val</code></a> 来检测。</p>
<p>如果某类型的所有的值都具有相同的尺寸和对齐量，并且两者在编译时都是已知的，并且实现了 <a href="https://doc.rust-lang.org/std/marker/trait.Sized.html"><code>Sized</code></a> trait，则可以使用函数 <a href="https://doc.rust-lang.org/std/mem/fn.size_of.html"><code>size_of</code></a> 和 <a href="https://doc.rust-lang.org/std/mem/fn.align_of.html"><code>align_of</code></a> 对此类型进行检测。没有实现 <code>Sized</code> trait 的类型被称为<a href="dynamically-sized-types.html">动态尺寸类型</a>。由于实现了 <code>Sized</code> trait 的某一类型的所有值共享相同的尺寸和对齐量，所以我们分别将这俩共享值称为该类型的尺寸和该类型的对齐量。</p>
<h2><a class="header" href="#primitive-data-layout" id="primitive-data-layout">Primitive Data Layout</a></h2>
<h2><a class="header" href="#原生类型的布局" id="原生类型的布局">原生类型的布局</a></h2>
<p>下表给出了大多数原生类型(primitives)的尺寸。</p>
<table><thead><tr><th>类型</th><th><code>size_of::&lt;Type&gt;()</code></th></tr></thead><tbody>
<tr><td><code>bool</code></td><td>1</td></tr>
<tr><td><code>u8</code> / <code>i8</code></td><td>1</td></tr>
<tr><td><code>u16</code> / <code>i16</code></td><td>2</td></tr>
<tr><td><code>u32</code> / <code>i32</code></td><td>4</td></tr>
<tr><td><code>u64</code> / <code>i64</code></td><td>8</td></tr>
<tr><td><code>u128</code> / <code>i128</code></td><td>16</td></tr>
<tr><td><code>f32</code></td><td>4</td></tr>
<tr><td><code>f64</code></td><td>8</td></tr>
<tr><td><code>char</code></td><td>4</td></tr>
</tbody></table>
<p><code>usize</code> 和 <code>isize</code> 的尺寸足以包含目标平台上的每个内存地址。例如，在 32-bit 目标上，它们是 4 个字节，而在 64-bit 目标上，它们是 8 个字节。</p>
<p>大多数原生类型的对齐量通常与它们的尺寸保持一致，尽管这是特定于平台的行为。比较典型的就是在 x86 平台上，u64 和 f64 都上 32-bit 的对齐量。</p>
<h2><a class="header" href="#pointers-and-references-layout" id="pointers-and-references-layout">Pointers and References Layout</a></h2>
<h2><a class="header" href="#指针和引用的布局" id="指针和引用的布局">指针和引用的布局</a></h2>
<p>指针和引用具有相同的布局。指针或引用的可变性不会影响其布局。</p>
<p>指向固定尺寸类型(sized type)的值的指针具有和 <code>usize</code> 相同的尺寸和对齐量。</p>
<p>指向非固定尺寸类型(unsized types)的值的指针是固定尺寸的。其尺寸和对齐量至少等于一个指针的尺寸和对齐量</p>
<blockquote>
<p>注意：虽然不应该依赖于此，但是目前所有指向 <abbr title="Dynamically Sized Types">DST</abbr> 的指针都是 <code>usize</code> 的两倍尺寸，并且具有相同的对齐量。</p>
</blockquote>
<h2><a class="header" href="#array-layout" id="array-layout">Array Layout</a></h2>
<h2><a class="header" href="#数组的布局" id="数组的布局">数组的布局</a></h2>
<p>数组 <code>[T; N]</code> 的尺寸为 <code>size_of::&lt;T&gt;() * N</code>，对齐量和 <code>T</code> 的对齐量相同。所以数组的布局使得数组的第 n 个(<code>nth</code>)元素（其中索引 n 是从0开始的）为从数组开始的位置向后偏移 <code>n * size_of::&lt;T&gt;()</code> 个字节数。</p>
<h2><a class="header" href="#slice-layout" id="slice-layout">Slice Layout</a></h2>
<h2><a class="header" href="#切片的布局" id="切片的布局">切片的布局</a></h2>
<p>切片的布局与它们所切的那部分数组片段相同。</p>
<blockquote>
<p>注意：这是关于原生的 <code>[T]</code>类型，而不是指向切片的指针（<code>&amp;[T]</code>、<code>Box&lt;[T]&gt;</code> 等）。</p>
</blockquote>
<h2><a class="header" href="#str-layout" id="str-layout"><code>str</code> Layout</a></h2>
<h2><a class="header" href="#字符串切片str的布局" id="字符串切片str的布局">字符串切片(<code>str</code>)的布局</a></h2>
<p>字符串切片是一种 UTF-8 表示形式(representation)的字符序列，它们与 <code>[u8]</code>类型的切片拥有相同的类型布局。</p>
<h2><a class="header" href="#tuple-layout" id="tuple-layout">Tuple Layout</a></h2>
<h2><a class="header" href="#元组的布局" id="元组的布局">元组的布局</a></h2>
<p>元组对于其布局没有任何保证。</p>
<p>一个例外情况是单元结构体(unit tuple)(<code>()</code>)类型，它被保证为尺寸为 0，对齐量为 1。</p>
<h2><a class="header" href="#trait-object-layout" id="trait-object-layout">Trait Object Layout</a></h2>
<h2><a class="header" href="#trait对象的布局" id="trait对象的布局">trait对象的布局</a></h2>
<p>trait对象的布局与 trait对象的值相同。</p>
<blockquote>
<p>注意：这是关于原生 trait对象类型(raw trait object type)的，而不是指向 trait对象的指针（<code>&amp;dyn Trait</code>， <code>Box&lt;dyn Trait&gt;</code> 等）。</p>
</blockquote>
<h2><a class="header" href="#closure-layout" id="closure-layout">Closure Layout</a></h2>
<h2><a class="header" href="#闭包的布局" id="闭包的布局">闭包的布局</a></h2>
<p>闭包的布局没有保证。</p>
<h2><a class="header" href="#representations" id="representations">Representations</a></h2>
<h2><a class="header" href="#表形表示形式" id="表形表示形式">表形/表示形式</a></h2>
<p>所有用户定义的复合类型（结构体(<code>struct</code>)、枚举(<code>enum</code>)和联合体(<code>union</code>)）都有一个*表形(representation)*属性，该属性用于指定该类型的布局。类型的可能表形有：</p>
<ul>
<li><a href="type-layout.html#the-default-representation">默认(default)表形</a></li>
<li><a href="type-layout.html#the-c-representation"><code>C</code>表形</a></li>
<li><a href="type-layout.html#primitive-representations">原语表形(primitive representation)</a></li>
<li><a href="type-layout.html#the-transparent-representation">透明表形(<code>transparent</code>)</a></li>
</ul>
<p>类型的表形可以通过对其应用 <code>repr</code>属性来更改。下面的示例展示了一个 <code>C</code>表形的结构体。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(C)]
struct ThreeInts {
    first: i16,
    second: i8,
    third: i32
}
<span class="boring">}
</span></code></pre></pre>
<p>可以分别使用 <code>align</code> 和 <code>packed</code> 修饰符增大或缩小对齐量。它们可以更改属性中指定表形的对齐量。如果未指定表形，则更改默认表形的。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 默认表形，把对齐量缩小到2。
#[repr(packed(2))]
struct PackedStruct {
    first: i16,
    second: i8,
    third: i32
}

// C表形，把对齐量增大到8
#[repr(C, align(8))]
struct AlignedStruct {
    first: i16,
    second: i8,
    third: i32
}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意：由于表形是程序项的属性，因此表形不依赖于泛型参数。具有相同名称的任何两种类型都具有相同的表形。例如，<code>Foo&lt;Bar&gt;</code> 和 <code>Foo&lt;Baz&gt;</code> 都有相同的表形。</p>
</blockquote>
<p>类型的表形可以更改字段之间的填充，但不会更改字段本身的布局。例如一个使用 <code>C</code>表形的结构体，如果它包含一个默认表形的字段 <code>Inner</code>，那么它不会改变 <code>Inner</code> 的布局。</p>
<h3><a class="header" href="#the-default-representation" id="the-default-representation">The Default Representation</a></h3>
<h3><a class="header" href="#默认表形" id="默认表形">默认表形</a></h3>
<p>没有 <code>repr</code>属性的标称(nominal)类型具有默认表形。非正式地的情况下，也称这种表形为 <code>rust</code>表形。</p>
<p>这种表形不保证每次编译都有统一的数据布局。</p>
<h3><a class="header" href="#the-c-representation" id="the-c-representation">The <code>C</code> Representation</a></h3>
<h3><a class="header" href="#c表形" id="c表形"><code>C</code>表形</a></h3>
<p><code>C</code>表形被设计用于双重目的：一个目的是创建可以与 C语言互操作的类型；第二个目的是创建可以正确执行依赖于数据布局的操作的类型，比如将值重新解释为其他类型。</p>
<p>因为这种双重目的存在，可以只利用其中的一个目的，如只创建有固定布局的类型，而放弃与 C语言的互操作。</p>
<p>这种表型可以应用于结构体(structs)、联合体(unions)和枚举(enums)。一个例外是<a href="items/enumerations.html#zero-variant-enums">零变体枚举(zero-variant enums)</a>，它的 <code>C</code>表形是错误的。</p>
<h4><a class="header" href="#reprc-structs" id="reprc-structs"><code>#[repr(C)]</code> Structs</a></h4>
<h4><a class="header" href="#reprc结构体" id="reprc结构体"><code>#[repr(C)]</code>结构体</a></h4>
<p>结构体的对齐量是其*最大对齐量的字段(most-aligned field)*的对齐量。</p>
<p>字段的尺寸和偏移量则由以下算法确定：</p>
<ol>
<li>
<p>把当前偏移量设为从 0 字节开始。</p>
</li>
<li>
<p>对于结构体中的每个字段，按其声明的先后顺序，首先确定其尺寸和对齐量；如果当前偏移量不是对其齐量的整倍数，则向当前偏移量添加填充字节，直至其对齐量的倍数<sup class="footnote-reference"><a href="#译注1">1</a></sup>；至此，当前字段的偏移量就是当前偏移量；下一步再根据当前字段的尺寸增加当前偏移量。</p>
</li>
<li>
<p>最后，整个结构体的尺寸就是当前偏移量向上取整到结构体对齐量的最小整数倍数。</p>
</li>
</ol>
<p>下面用伪代码描述这个算法：</p>
<!-- ignore: pseudocode -->
<pre><code class="language-rust ignore">/// 返回偏移(`offset`)之后需要的填充量，以确保接下来的地址将被安排到可对齐的地址。
fn padding_needed_for(offset: usize, alignment: usize) -&gt; usize {
    let misalignment = offset % alignment;
    if misalignment &gt; 0 {
        // 向上取整到对齐量(`alignment`)的下一个倍数
        alignment - misalignment
    } else {
        // 已经是对齐量(`alignment`)的倍数了
        0
    }
}

struct.alignment = struct.fields().map(|field| field.alignment).max();

let current_offset = 0;

for field in struct.fields_in_declaration_order() {
    // 增加当前字的偏移量段(`current_offset`)，使其成为该字段对齐量的倍数。
    // 对于第一个字段，此值始终为零。
    // 跳过的字节称为填充字节。
    current_offset += padding_needed_for(current_offset, field.alignment);

    struct[field].offset = current_offset;

    current_offset += field.size;
}

struct.size = current_offset + padding_needed_for(current_offset, struct.alignment);
</code></pre>
<div class="warning">
<p>警告:这个伪代码使用了一个简单粗暴的算法，是为了清晰起见，它忽略了溢出问题。要在实际代码中执行内存布局计算，请使用 <a href="https://doc.rust-lang.org/std/alloc/struct.Layout.html"><code>Layout</code></a>。</p>
</div>
<blockquote>
<p>注意：此算法可以生成零尺寸的结构体。在 C 语言中，像 <code>struct Foo { }</code> 这样的空结构体声明是非法的。然而，gcc 和 clang 都支持启用此类结构体的选项，并将其尺寸指定为零。跟 Rust 不同的是 C++ 给空结构体指定的尺寸为 1，并且除非它们是继承的，否则它们是具有 <code>[[no_unique_address]]</code> 属性的字段（在这种情况下，它们不会增大结构体的整体尺寸）。</p>
</blockquote>
<h4><a class="header" href="#reprc-unions" id="reprc-unions"><code>#[repr(C)]</code> Unions</a></h4>
<h4><a class="header" href="#reprc联合体" id="reprc联合体"><code>#[repr(C)]</code>联合体</a></h4>
<p>使用 <code>#[repr(C)]</code> 声明的联合体将与相同目标平台上的 C语言中的 C联合体声明具有相同的尺寸和对齐量。联合体的对齐量等同于其所有字段的最大对齐量，尺寸将为其所有字段的最大尺寸，再对其向上取整到对齐量的最小整数倍。这些最大值可能来自不同的字段。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(C)]
union Union {
    f1: u16,
    f2: [u8; 4],
}

assert_eq!(std::mem::size_of::&lt;Union&gt;(), 4);  // 来自于 f2
assert_eq!(std::mem::align_of::&lt;Union&gt;(), 2); // 来自于 f1

#[repr(C)]
union SizeRoundedUp {
   a: u32,
   b: [u16; 5],
}

assert_eq!(std::mem::align_of::&lt;SizeRoundedUp&gt;(), 4); // 来自于 a

assert_eq!(std::mem::size_of::&lt;SizeRoundedUp&gt;(), 12);  // 首先来自于b的尺寸10，然后向上取整到最近的4的整数倍12。

<span class="boring">}
</span></code></pre></pre>
<h4><a class="header" href="#reprc-field-less-enums" id="reprc-field-less-enums"><code>#[repr(C)]</code> Field-less Enums</a></h4>
<h4><a class="header" href="#reprc无字段枚举" id="reprc无字段枚举"><code>#[repr(C)]</code>无字段枚举</a></h4>
<p>对于<a href="items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations">无字段枚举(field-less enums)</a>，<code>C</code>表形的尺寸和对齐量与目标平台的 C ABI 的默认枚举尺寸和对齐量相同。</p>
<blockquote>
<p>注意：C中的枚举的表形是由枚举的相应实现定义的，所以在 Rust 中，给无字段枚举应用 C表形得到的表型很可能是一个“最佳猜测”。特别是，当使用某些特定命令行参数来编译特定的 C代码时，这可能是不正确的。</p>
</blockquote>
<div class="warning">
<p>警告：C语言中的枚举与 Rust 中的那些应用了 <code>#[repr(C)]</code>表型的<a href="items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations">无字段枚举</a>之间有着重要的区别。C语言中的枚举主要是 <code>typedef</code> 加上一些具名常量；换句话说，C枚举(<code>enum</code>)类型的对象可以包含任何整数值。例如，C枚举通常被用做标志位。相比之下，Rust的<a href="items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations">无字段枚举</a>只能合法地<sup class="footnote-reference"><a href="#译注2">2</a></sup>保存判别式的值，其他的都是<a href="behavior-considered-undefined.html">未定义行为</a>。因此，在 FFI 中使用无字段枚举来建模 C语言中的枚举(<code>enum</code>)通常是错误的。</p>
</div>
<h4><a class="header" href="#reprc-enums-with-fields" id="reprc-enums-with-fields"><code>#[repr(C)]</code> Enums With Fields</a></h4>
<h4><a class="header" href="#reprc带字段枚举" id="reprc带字段枚举"><code>#[repr(C)]</code>带字段枚举</a></h4>
<p>带字段的 <code>repr(C)</code>枚举的表形其实等效于一个带两个字段的 <code>repr(C)</code>结构体（这种在 C语言中也被称为“标签联合(tagged union)”），这两个字段：</p>
<ul>
<li>一个为 <code>repr(C)</code>表形的枚举（在这个等效结构体内，它也被叫做标签(the tag)字段），它就是原枚举所有的判别值组合成的新枚举，也就是它的变体是原枚举变体移除了它们自身所带的所有字段。</li>
<li>一个为 <code>repr(C)</code>表形的联合体（在这个等效结构体内，它也被叫做载荷(the payload)字段），它的各个字段就是原枚举的各个变体把自己下面的字段重新组合成的 <code>repr(C)</code>表形的结构体。</li>
</ul>
<blockquote>
<p>注意：由于等效出的结构体和联合体是 <code>repr(C)</code>表形的，因此如果原来某一变体只有单个字段，则直接将该字段放入等效出的联合体中，或将其包装进一个次级结构体后再放入联合体中是没有区别的；因此，任何希望操作此类枚举表形的系统都可以选择使用这两种形式里对它们来说更方便或更一致的形式。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 这个枚举的表形等效于 ...
#[repr(C)]
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
 }

// ... 这个结构体
#[repr(C)]
struct MyEnumRepr {
    tag: MyEnumDiscriminant,
    payload: MyEnumFields,
}

// 这是原判别值组成的新枚举类型.
#[repr(C)]
enum MyEnumDiscriminant { A, B, C, D }

// 这是原变体的字段组成的联合体.
#[repr(C)]
union MyEnumFields {
    A: MyAFields,   // 译者注：因为原枚举变体A只有一个字段，所以此处的类型标注也可以直接替换为 u32,以省略 MyAFields这层封装
    B: MyBFields,
    C: MyCFields,
    D: MyDFields,
}

#[repr(C)]
#[derive(Copy, Clone)]
struct MyAFields(u32);

#[repr(C)]
#[derive(Copy, Clone)]
struct MyBFields(f32, u64);

#[repr(C)]
#[derive(Copy, Clone)]
struct MyCFields { x: u32, y: u8 }

// 这个结构体可以被省略(它是一个零尺寸类型)，但它必须出现在 C/C++ 头文件中
#[repr(C)]
#[derive(Copy, Clone)]
struct MyDFields;
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意： 联合体(<code>union</code>)可带有未实现 <code>Copy</code> 的字段的功能还没有纳入稳定版，具体参见 <a href="https://github.com/rust-lang/rust/issues/55149">55149</a>。</p>
</blockquote>
<h3><a class="header" href="#primitive-representations" id="primitive-representations">Primitive representations</a></h3>
<h3><a class="header" href="#原语表形" id="原语表形">原语表形</a></h3>
<p><em>原语表形</em>是与原生整型具有相同名称的表形。也就是：<code>u8</code>，<code>u16</code>，<code>u32</code>，<code>u64</code>，<code>u128</code>，<code>usize</code>，<code>i8</code>，<code>i16</code>，<code>i32</code>，<code>i64</code>，<code>i128</code> 和 <code>isize</code>。</p>
<p>原语表形只能应用于枚举，此时枚举有没有字段会给原语表形带来不同的表现。给<a href="items/enumerations.html#zero-variant-enums">零变体枚举</a>应用原始表形是错误的。将两个原语表形组合在一起也是错误的</p>
<h4><a class="header" href="#primitive-representation-of-field-less-enums" id="primitive-representation-of-field-less-enums">Primitive Representation of Field-less Enums</a></h4>
<h4><a class="header" href="#无字段枚举的原语表形" id="无字段枚举的原语表形">无字段枚举的原语表形</a></h4>
<p>对于<a href="items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations">无字段枚举</a>，原语表形将其尺寸和对齐量设置成与给定表形同名的原生类型的表形的值。例如，一个 <code>u8</code>表形的无字段枚举只能有0和255之间的判别值。</p>
<h4><a class="header" href="#primitive-representation-of-enums-with-fields" id="primitive-representation-of-enums-with-fields">Primitive Representation of Enums With Fields</a></h4>
<h4><a class="header" href="#带字段枚举的原语表形" id="带字段枚举的原语表形">带字段枚举的原语表形</a></h4>
<p>带字段枚举的原语表形是一个 <code>repr(C)</code>表形的联合体，此联合体的每个字段对应一个和原枚举变体对应的 <code>repr(C)</code>表形的结构体。这些结构体的第一个字段是原枚举的变体移除了它们所有的字段组成的原语表形版的无字段枚举（“the tag”），那这些结构体的其余字段是原变体移走的字段。</p>
<blockquote>
<p>注意：如果在联合体中，直接把标签的成员赋予给标签(“the tag”)，那么这种表形结构仍不变的，并且这样操作对您来说可能会更清晰（尽管遵循 c++ 的标准，标签也应该被包装在结构体中）。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 这个枚举的表形效同于 ...
#[repr(u8)]
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
 }

// ... 这个联合体.
#[repr(C)]
union MyEnumRepr {
    A: MyVariantA,  //译者注：此字段类型也可直接用 u32 直接替代
    B: MyVariantB,  //译者注：此字段类型也可直接用 (f32, u64) 直接替代
    C: MyVariantC,
    D: MyVariantD,
}

// 这是原判别值组合成的新枚举。
#[repr(u8)]
#[derive(Copy, Clone)]
enum MyEnumDiscriminant { A, B, C, D }

#[repr(C)]
#[derive(Clone, Copy)]
struct MyVariantA(MyEnumDiscriminant, u32);

#[repr(C)]
#[derive(Clone, Copy)]
struct MyVariantB(MyEnumDiscriminant, f32, u64);

#[repr(C)]
#[derive(Clone, Copy)]
struct MyVariantC { tag: MyEnumDiscriminant, x: u32, y: u8 }

#[repr(C)]
#[derive(Clone, Copy)]
struct MyVariantD(MyEnumDiscriminant);
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>注意： 联合体(<code>union</code>)带有未实现 <code>Copy</code> trait 的字段的功能还没有纳入稳定版，具体参见 <a href="https://github.com/rust-lang/rust/issues/55149">55149</a>。</p>
</blockquote>
<h4><a class="header" href="#combining-primitive-representations-of-enums-with-fields-and-reprc" id="combining-primitive-representations-of-enums-with-fields-and-reprc">Combining primitive representations of enums with fields and <code>#[repr(C)]</code></a></h4>
<h4><a class="header" href="#带字段枚举的原语表形与reprc表形的组合使用" id="带字段枚举的原语表形与reprc表形的组合使用">带字段枚举的原语表形与<code>#[repr(C)]</code>表形的组合使用</a></h4>
<p>对于带字段枚举，还可以将 <code>repr(C)</code> 和原语表形（例如，<code>repr(C, u8)</code>）结合起来使用。这是通过将判别值组成的枚举的表形改为原语表形来实现的。因此，如果选择组合 <code>u8</code>表形，那么组合出的判别值枚举的尺寸和对齐量将为 1 个字节。</p>
<p>那么这个判别值枚举就从<a href="type-layout.html#reprc-enums-with-fields">前面</a>示例中的样子变成：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(C, u8)] // 这里加上了 `u8`
enum MyEnum {
    A(u32),
    B(f32, u64),
    C { x: u32, y: u8 },
    D,
 }

// ...

#[repr(u8)] // 所以这里就用 `u8` 替代了 `C`
enum MyEnumDiscriminant { A, B, C, D }

// ...
<span class="boring">}
</span></code></pre></pre>
<p>例如，对于有 <code>repr(C, u8)</code>属性的枚举，不可能有257个唯一的判别值（“tags”），而同一个枚举，如果只有单一 <code>repr(C)</code>表形属性，那在编译时就不会出任何问题。</p>
<p>在 <code>repr(C)</code> 附加原语表形可以改变 <code>repr(C)</code>表形的枚举的尺寸：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[repr(C)]
enum EnumC {
    Variant0(u8),
    Variant1,
}

#[repr(C, u8)]
enum Enum8 {
    Variant0(u8),
    Variant1,
}

#[repr(C, u16)]
enum Enum16 {
    Variant0(u8),
    Variant1,
}

// C表形的尺寸依赖于平台
assert_eq!(std::mem::size_of::&lt;EnumC&gt;(), 8);
// 一个字节用于判别值，一个字节用于 Enum8::Variant0 中的值
assert_eq!(std::mem::size_of::&lt;Enum8&gt;(), 2);
// 两个字节用于判别值，一个字节用于Enum16::Variant0中的值，加上一个字节的填充
assert_eq!(std::mem::size_of::&lt;Enum16&gt;(), 4);
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#the-alignment-modifiers" id="the-alignment-modifiers">The alignment modifiers</a></h3>
<h3><a class="header" href="#对齐量的修饰符" id="对齐量的修饰符">对齐量的修饰符</a></h3>
<p><code>align</code> 和 <code>packed</code> 修饰符可分别用于增大和减小结构体的和联合体的对齐量。<code>packed</code> 也可以改变字段之间的填充。</p>
<p>对齐量被指定为整型参数，形式为 <code>#[repr(align(x))]</code> 或 <code>#[repr(packed(x))]</code>。对齐量的值必须是从1到2<sup>29</sup>之间的2的次幂数。对于 <code>packed</code>，如果没有给出任何值，如 <code>#[repr(packed)]</code>，则对齐量的值为1。</p>
<p>对于 <code>align</code>，如果类型指定的对齐量比其不带 <code>align</code>修饰符时的对齐量小，则该指定的对齐量无效。</p>
<p>对于 <code>packed</code>，如果类型指定的对齐量比其不带 <code>packed</code>修饰符时的对齐量大，则该指定的对齐量和布局无效。为了定位字段，每个字段的对齐量是指定的对齐量和字段的类型的对齐量中较小的那个对齐量。</p>
<p><code>align</code> 和 <code>packed</code> 修饰符不能应用于同一类型，且 <code>packed</code> 修饰的类型不能直接或间接地包含另一个 <code>align</code> 修饰的类型。<code>align</code> 和 <code>packed</code> 修饰符只能应用于<a href="type-layout.html#the-default-representation">默认表形</a>和 <a href="type-layout.html#the-c-representation">C表形</a>中。</p>
<p><code>align</code>修饰符也可以应用在枚举上。如果这样做了，其对枚举对齐量的影响与将此枚举包装在一个新的使用了相同的 <code>align</code>修饰符的结构体中的效果相同。</p>
<div class="warning">
<p>***警告：***解引用一个未对齐的指针是<a href="behavior-considered-undefined.html">未定义行为</a>，但可以<a href="https://github.com/rust-lang/rust/issues/27060">安全地创建指向 <code>packed</code>修饰的字段的未对齐指针</a>。就像在安全(safe) Rust 中所有创建未定义行为的方法一样，这是一个 bug。</p>
</div>
<h3><a class="header" href="#the-transparent-representation" id="the-transparent-representation">The <code>transparent</code> Representation</a></h3>
<h3><a class="header" href="#透明transparent表形" id="透明transparent表形">透明(<code>transparent</code>)表形</a></h3>
<p>透明(<code>transparent</code>)表型只能在只有一个字段的<a href="items/structs.html">结构体(<code>struct</code>)</a>上或只有一个变体的<a href="items/enumerations.html">枚举(<code>enum</code>)</a>上使用，这里只有一个字段/变体的意思是：</p>
<ul>
<li>只能有一个非零尺寸的字段/变体，和</li>
<li>任意数量的尺寸为零对齐量为1的字段（例如：<a href="special-types-and-traits.html#phantomdatat"><code>PhantomData&lt;T&gt;</code></a>）</li>
</ul>
<p>使用这种表形的结构体和枚举与只有那个非零尺寸的字段具有相同的布局和 ABI。</p>
<p>这与 <code>C</code>表形不同，因为带有 <code>C</code>表形的结构体将始终拥有 C结构体(<code>C</code> <code>struct</code>)的ABI，例如，那些只有一个原生类型字段的结构体如果应用了透明表形(<code>transparent</code>)，将具有此原生类型字段的ABI。</p>
<p>因为此表形将类型布局委托给另一种类型，所以它不能与任何其他表形一起使用。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>至此，上一个字段就填充完成，开始计算本字段了。也就是说每一个字段的偏移量是其字段的段首位置；那第一个字段的偏移量就始终为 0。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">2</sup>
<p>这里合法的意思是变体的判别值受 <code>repr(u8)</code> 这样的表形属性约束，像这个例子中，变体的判别值就只能位于 0~255 之间。 </p>
</div>
<!-- 2020-12-17-->
<!-- checked -->
<h1><a class="header" href="#interior-mutability" id="interior-mutability">Interior Mutability</a></h1>
<h1><a class="header" href="#内部可变性" id="内部可变性">内部可变性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/interior-mutability.md">interior-mutability.md</a><br />
commit: e7dd3618d78928322f53a20e2947e428b12eda2b <br />
本章译文最后维护日期：2020-11-15</p>
</blockquote>
<p>有时一个类型需要在存在多个别名时进行更改。在 Rust 中，这是通过一种叫做<em>内部可变性</em>的模式实现的。如果一个类型的内部状态可以通过对它的<a href="types/pointer.html#shared-references-">共享引用</a>来进行更改，那么就说这个类型就具有内部可变性。这违背了共享引用所指向的值不能被更改的通常<a href="behavior-considered-undefined.html">要求</a>。</p>
<p><a href="https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html"><code>std::cell::UnsafeCell&lt;T&gt;</code></a>类型是 Rust 中唯一可以合法失效此要求的方法。当 <code>UnsafeCell&lt;T&gt;</code> 存在其他不变性的别名<sup class="footnote-reference"><a href="#译注1">1</a></sup>时，仍然可以安全地对它包含的 <code>T</code> 进行更改或获得 <code>T</code> 的一个可变引用。与所有其他类型一样，拥有多个 <code>&amp;mut UnsafeCell&lt;T&gt;</code> 别名是未定义行为。</p>
<p>通过使用 <code>UnsafeCell&lt;T&gt;</code> 作为字段，可以创建具有内部可变性的其他类型。标准库提供了几种这样的类型，这些类型都提供了安全的内部变更的 API。例如，<a href="https://doc.rust-lang.org/std/cell/struct.RefCell.html"><code>std::cell::RefCell&lt;T&gt;</code></a> 使用运行时借用检查来确保多个引用存在时的常规规则的执行。<a href="https://doc.rust-lang.org/std/sync/atomic/index.html"><code>std::sync::atomic</code></a>模块包含了一些类型，这些类型包装了一个只能通过原子操作访问的值，以允许在线程之间共享和修改该值。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>当变量和指针表示的内存区域有重叠时，它们互为对方的别名。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#subtyping-and-variance" id="subtyping-and-variance">Subtyping and Variance</a></h1>
<h1><a class="header" href="#子类型化和型变" id="子类型化和型变">子类型化和型变</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/subtyping.md">subtyping.md</a><br />
commit: 3b6fe80c205d2a2b5dc8a276192bbce9eeb9e9cf <br />
本章译文最后维护日期：2021-03-02</p>
</blockquote>
<p>子类型化是隐式的，可以出现在类型检查或类型推断的任何阶段。
Rust 中的子类型化的适用范围非常有限，仅出现在和生存期(lifetimes)的型变(variance)相关的地方，以及那些和高阶生存期相关的类型型变之间。
如果我们擦除了类型的生存期，那么唯一的子类型化就只是类型相等(type equality)了。</p>
<p>考虑下面的例子：字符串字面量总是拥有 <code>'static</code>生存期。不过，我们还是可以把 <code>s</code> 赋值给 <code>t</code>：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn bar&lt;'a&gt;() {
    let s: &amp;'static str = &quot;hi&quot;;
    let t: &amp;'a str = s;
}
<span class="boring">}
</span></code></pre></pre>
<p>因为 <code>'static</code> 比生存期参数 <code>'a</code> 的寿命长，所以 <code>&amp;'static str</code> 是 <code>&amp;'a str</code> 的子类型。</p>
<p><a href="https://doc.rust-lang.org/nomicon/hrtb.html">高阶</a><a href="types/function-pointer.html">函数指针</a>和<a href="types/trait-object.html">trait对象</a>可以形成另一种父子类型的关系。
它们是那些通过替换高阶生存期而得出的类型的子类型。举些例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 这里 'a 被替换成了 'static
let subtype: &amp;(for&lt;'a&gt; fn(&amp;'a i32) -&gt; &amp;'a i32) = &amp;((|x| x) as fn(&amp;_) -&gt; &amp;_);
let supertype: &amp;(fn(&amp;'static i32) -&gt; &amp;'static i32) = subtype;

// 这对于 trait对象也是类似的
let subtype: &amp;(for&lt;'a&gt; Fn(&amp;'a i32) -&gt; &amp;'a i32) = &amp;|x| x;
let supertype: &amp;(Fn(&amp;'static i32) -&gt; &amp;'static i32) = subtype;

// 我们也可以用一个高阶生存期来代替另一个
let subtype: &amp;(for&lt;'a, 'b&gt; fn(&amp;'a i32, &amp;'b i32))= &amp;((|x, y| {}) as fn(&amp;_, &amp;_));
let supertype: &amp;for&lt;'c&gt; fn(&amp;'c i32, &amp;'c i32) = subtype;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#variance" id="variance">Variance</a></h2>
<h2><a class="header" href="#型变" id="型变">型变</a></h2>
<p>型变是泛型类型相对其参数具有的属性。
泛型类型在它的某个参数上的<em>型变</em>是描述该参数的子类型化去如何影响此泛型类型的子类型化。</p>
<ul>
<li>如果 <code>T</code> 是 <code>U</code> 的一个子类型意味着 <code>F&lt;T&gt;</code> 是 <code>F&lt;U&gt;</code> 的一个子类型（即子类型化“通过(passes through)”），则 <code>F&lt;T&gt;</code> 在 <code>T</code> 上是<em>协变的(covariant)</em>。</li>
<li>如果 <code>T</code> 是 <code>U</code> 的一个子类型意味着 <code>F&lt;U&gt;</code> 是 <code>F&lt;T&gt;</code> 的一个子类型，则 <code>F&lt;T&gt;</code> 在 <code>T</code> 上是<em>逆变的(contravariant)</em>。</li>
<li>其他情况下（即不能由参数类型的子类型化关系推导出此泛型的型变关系），<code>F&lt;T&gt;</code> 在 <code>T</code> 上是的<em>不变的(invariant)</em>。</li>
</ul>
<p>类型的型变关系由下表中的规则自动确定：</p>
<table><thead><tr><th>Type</th><th>在 <code>'a</code> 上的型变</th><th>在 <code>T</code> 上的型变</th></tr></thead><tbody>
<tr><td><code>&amp;'a T</code></td><td>协变的</td><td>协变的</td></tr>
<tr><td><code>&amp;'a mut T</code></td><td>协变的</td><td>不变的</td></tr>
<tr><td><code>*const T</code></td><td></td><td>协变的</td></tr>
<tr><td><code>*mut T</code></td><td></td><td>不变的</td></tr>
<tr><td><code>[T]</code> 和 <code>[T; n]</code></td><td></td><td>协变的</td></tr>
<tr><td><code>fn() -&gt; T</code></td><td></td><td>协变的</td></tr>
<tr><td><code>fn(T) -&gt; ()</code></td><td></td><td>逆变的</td></tr>
<tr><td><code>fn(T) -&gt; T</code></td><td></td><td>不变的</td></tr>
<tr><td><code>std::cell::UnsafeCell&lt;T&gt;</code></td><td></td><td>不变的</td></tr>
<tr><td><code>std::marker::PhantomData&lt;T&gt;</code></td><td></td><td>协变的</td></tr>
<tr><td><code>dyn Trait&lt;T&gt; + 'a</code></td><td>协变的</td><td>不变的</td></tr>
</tbody></table>
<p>结构体(<code>struct</code>)、枚举(<code>enum</code>)、联合体(<code>union</code>)和元组(tuple)类型上的型变关系是通过查看其字段类型的型变关系来决定的。
如果参数用在了多处且具有不同型变关系的位置上，则该类型在该参数上是不变的。
例如，下面示例的结构体在 <code>'a</code> 和 <code>T</code> 上是协变的，在 <code>'b</code> 和 <code>U</code> 上是不变的。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::cell::UnsafeCell;
struct Variance&lt;'a, 'b, T, U: 'a&gt; {
    x: &amp;'a U,               // 这让 `Variance` 在 'a 上是协变的, 也让在 U 上是协变的, 但是后面也使用了 U
    y: *const T,            // 在 T 上是协变的
    z: UnsafeCell&lt;&amp;'b f64&gt;, // 在 'b 上是不变的
    w: *mut U,              // 在 U 上是不变的, 所以让整个结构体在 U 上是不变的
}
<span class="boring">}
</span></code></pre></pre>
<h1><a class="header" href="#trait-and-lifetime-bounds" id="trait-and-lifetime-bounds">Trait and lifetime bounds</a></h1>
<h1><a class="header" href="#trait约束和生存期约束" id="trait约束和生存期约束">trait约束和生存期约束</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/trait-bounds.md">trait-bounds.md</a><br />
commit: 82d75cf423e4a7824fb36e73ccb18519d6900610 <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>TypeParamBounds</em> :<br />
   <em>TypeParamBound</em> ( <code>+</code> <em>TypeParamBound</em> )<sup>*</sup> <code>+</code><sup>?</sup></p>
<p><em>TypeParamBound</em> :<br />
      <em>Lifetime</em> | <em>TraitBound</em></p>
<p><em>TraitBound</em> :<br />
      <code>?</code><sup>?</sup>
<a href="trait-bounds.html#higher-ranked-trait-bounds"><em>ForLifetimes</em></a><sup>?</sup> <a href="paths.html#paths-in-types"><em>TypePath</em></a><br />
   | <code>(</code> <code>?</code><sup>?</sup>
<a href="trait-bounds.html#higher-ranked-trait-bounds"><em>ForLifetimes</em></a><sup>?</sup> <a href="paths.html#paths-in-types"><em>TypePath</em></a> <code>)</code></p>
<p><em>LifetimeBounds</em> :<br />
   ( <em>Lifetime</em> <code>+</code> )<sup>*</sup> <em>Lifetime</em><sup>?</sup></p>
<p><em>Lifetime</em> :<br />
      <a href="tokens.html#lifetimes-and-loop-labels">LIFETIME_OR_LABEL</a><br />
   | <code>'static</code><br />
   | <code>'_</code></p>
</blockquote>
<p><a href="items/traits.html#trait-bounds">trait</a>约束和生存期约束为<a href="items/generics.html">泛型程序项</a>提供了一种方法来限制将哪些类型和生存期可被用作它们的参数。通过 <a href="items/generics.html#where-clauses">where子句</a>可以为任何泛型提供约束。对于某些常见的情况，也可以使用如下简写形式：</p>
<ul>
<li>跟在<a href="items/generics.html">泛型参数</a>声明之后的约束：<code>fn f&lt;A: Copy&gt;() {}</code> 与 <code>fn f&lt;A&gt; where A: Copy () {}</code> 效果等价。</li>
<li>在 trait声明中作为指定<a href="items/traits.html#supertraits">超类trait(supertraits)</a> 约束时：<code>trait Circle : Shape {}</code> 等同于 <code>trait Circle where Self : Shape {}</code>。</li>
<li>在 trait声明中作为指定关联类型上的约束时：<code>trait A { type B: Copy; }</code> 等同于 <code>trait A where Self::B: Copy { type B; }</code>。</li>
</ul>
<p>在程序项上应用了约束就要求在使用该程序项时使用者必须满足这些约束。当对泛型程序项进行类型检查和借用检查时，约束可用来确认当前准备用来单态化此泛型的实例类型是否实现了约束给出的 trait。例如，给定 <code>Ty: Trait</code>：</p>
<ul>
<li>在泛型函数体中，<code>Trait</code> 中的方法可以被 <code>Ty</code>类型的值调用。同样，<code>Trait</code> 上的相关常数也可以被使用。</li>
<li><code>Trait</code> 上的关联类型可以被使用。</li>
<li>带有 <code>T: Trait</code>约束的泛型函数或类型可以在使用 <code>T</code> 的地方替换使用 <code>Ty</code>。</li>
</ul>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">type Surface = i32;
</span>trait Shape {
    fn draw(&amp;self, surface: Surface);
    fn name() -&gt; &amp;'static str;
}

fn draw_twice&lt;T: Shape&gt;(surface: Surface, sh: T) {
    sh.draw(surface);           // 能调用此方法上因为 T: Shape
    sh.draw(surface);
}

fn copy_and_draw_twice&lt;T: Copy&gt;(surface: Surface, sh: T) where T: Shape {
    let shape_copy = sh;        // sh 没有被使用移动语义移走，是因为 T: Copy
    draw_twice(surface, sh);    // 能使用泛型函数 draw_twice 是因为 T: Shape
}

struct Figure&lt;S: Shape&gt;(S, S);

fn name_figure&lt;U: Shape&gt;(
    figure: Figure&lt;U&gt;,          // 这里类型 Figure&lt;U&gt; 的格式正确是因为 U: Shape
) {
    println!(
        &quot;Figure of two {}&quot;,
        U::name(),              // 可以使用关联函数
    );
}
<span class="boring">}
</span></code></pre></pre>
<p>trait 和生存期约束也被用来命名 <a href="types/trait-object.html">trait对象</a>。</p>
<h2><a class="header" href="#sized" id="sized"><code>?Sized</code></a></h2>
<p><code>?</code> 仅用于放宽<a href="types/parameters.html">类型参数</a>或<a href="items/associated-items.html#associated-types">关联类型</a> 上的<a href="special-types-and-traits.html#sized"><code>Sized</code></a> trait。
目前 <code>?Sized</code> 还不能用作其他类型的约束。</p>
<h2><a class="header" href="#lifetime-bounds" id="lifetime-bounds">Lifetime bounds</a></h2>
<h2><a class="header" href="#生存期约束" id="生存期约束">生存期约束</a></h2>
<p>生存期约束可以应用于类型或其他生存期。
约束 <code>'a: 'b</code> 通常被读做 <em><code>'a</code> 比 <code>'b</code> 存活的时间久</em>。
<code>'a: 'b</code> 意味着 <code>'a</code> 持续的时间至少和 <code>'b</code> 一样长，所以只要 <code>&amp;'b ()</code> 有效，则 <code>&amp;'a ()</code> 就有效。<sup class="footnote-reference"><a href="#译注1">1</a></sup></p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn f&lt;'a, 'b&gt;(x: &amp;'a i32, mut y: &amp;'b i32) where 'a: 'b {
    y = x;                      // 因为 'a: 'b，所以&amp;'a i32 是 &amp;'b i32 的子类型
    let r: &amp;'b &amp;'a i32 = &amp;&amp;0;   // &amp;'b &amp;'a i32 格式合法是因为 'a: 'b
}
<span class="boring">}
</span></code></pre></pre>
<p><code>T: 'a</code> 意味着 <code>T</code> 的所有生存期参数都比 <code>'a</code> 存活得时间长。
例如，如果 <code>'a</code> 是一个任意的(unconstrained)生存期参数，那么 <code>i32: 'static</code> 和 <code>&amp;'static str: 'a</code> 都合法，但 <code>Vec&lt;&amp;'a ()&gt;: 'static</code> 不合法。</p>
<h2><a class="header" href="#higher-ranked-trait-bounds" id="higher-ranked-trait-bounds">Higher-ranked trait bounds</a></h2>
<h2><a class="header" href="#高阶trait约束" id="高阶trait约束">高阶trait约束</a></h2>
<blockquote>
<p><em>ForLifetimes</em> :<br />
   <code>for</code> <a href="items/generics.html"><em>GenericParams</em></a></p>
</blockquote>
<p>可以在生存期上再进行<em>更高阶的</em>类型约束。这些高阶约束指定了一个对<em>所有</em>生存期都为真的约束。例如，像 <code>for&lt;'a&gt; &amp;'a T: PartialEq&lt;i32&gt;</code> 这样的约束需要一个如下的实现</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct T;
</span>impl&lt;'a&gt; PartialEq&lt;i32&gt; for &amp;'a T {
    // ...
<span class="boring">   fn eq(&amp;self, other: &amp;i32) -&gt; bool {true}
</span>}
<span class="boring">}
</span></code></pre></pre>
<p>这样就可以拿任意生存期的 <code>&amp;'a T</code> 和 <code>i32</code> 做比较啦。</p>
<p>下面这类场景只能使用高阶trait约束，因为引用的生命周期比函数的生命周期参数短：<sup class="footnote-reference"><a href="#译注3">2</a></sup></p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn call_on_ref_zero&lt;F&gt;(f: F) where for&lt;'a&gt; F: Fn(&amp;'a i32) { 
    let zero = 0;
    f(&amp;zero);}
<span class="boring">}
</span></code></pre></pre>
<blockquote>
<p>译者注：译者下面举例代码可以和上面原文的代码对比着看。下面代码中，因为 <code>F</code> 没约束 <code>'a</code>，导致参数 <code>f</code> 引用了未经扩展生存期的 <code>zero</code></p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn call_on_ref_zero&lt;'a, F&gt;(f: F) where F: Fn(&amp;'a i32) {
   let zero = 0;
   f(&amp;zero);
}
<span class="boring">}
</span></code></pre></pre>
</blockquote>
<p>高阶生存期也可以在 trait 前面指定：唯一的区别是生存期参数的作用域，像下面这样 <code>'a</code> 的作用域只扩展到后面跟的 trait 的末尾，而不是整个约束<sup class="footnote-reference"><a href="#译注4">3</a></sup>。下面这个函数和上一个等价。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn call_on_ref_zero&lt;F&gt;(f: F) where F: for&lt;'a&gt; Fn(&amp;'a i32) {
    let zero = 0;
    f(&amp;zero);
}
<span class="boring">}
</span></code></pre></pre>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>译者理解：理解这种关系时，可以把生存期 <code>'a</code> 和 <code>'b</code> 理解成去引用对象时需传入的参数，给定 <code>'a: 'b</code> 和类型 <code>T</code>，如果 <code>'b T</code>有效，那此时再传入 <code>'a</code> 就去引用 <code>T</code> 必定有效。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">4</sup>
<p>译者理解：高阶 trait约束就是对带生存期的类型重新进行约束。像这句中的例子就是对 <code>&amp;'a T</code> 加上了 <code>PartialEq&lt;i32&gt;</code> 的约束，其中 <code>for&lt;'a&gt;</code> 可以理解为：对于 <code>'a</code> 的所有可能选择。更多信息请参见：https://doc.rust-lang.org/std/cmp/trait.PartialEq.html 和 https://doc.rust-lang.org/nightly/nomicon/hrtb.html</p>
</div>
<div class="footnote-definition" id="译注3"><sup class="footnote-definition-label">2</sup>
<p>译者理解此例中的代码 <code>for&lt;'a&gt; F: Fn(&amp;'a i32)</code> 为：<code>F</code> 对于 <code>'a</code> 的所有可能选择都受 <code>Fn(&amp;'a i32)</code> 的约束。</p>
</div>
<div class="footnote-definition" id="译注4"><sup class="footnote-definition-label">3</sup>
<p>译者理解这句的意思是：如果 <code>F</code> 的约束有多个 trait，那这种方式里， <code>'a</code> 的作用域只是扩展它后面紧跟的那个 trait 的方法，即 <code>Fn(&amp;'a i32)</code> 里。</p>
</div>
<h1><a class="header" href="#type-coercions" id="type-coercions">Type coercions</a></h1>
<h1><a class="header" href="#类型自动强转" id="类型自动强转">类型自动强转</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/type-coercions.md">type-coercions.md</a><br />
commit: d5a5e32d3cda8a297d2a91a85b91ff2629b0e896 <br />
本章译文最后维护日期：2020-11-15</p>
</blockquote>
<p><strong>类型自动强转</strong>是改变值的类型的隐式操作。它们在特定的位置自动发生，但实际自动强转的类型也受到很多限制。</p>
<p>任何允许自动强转的转换都可以由<a href="expressions/operator-expr.html#type-cast-expressions">类型强制转换操作符</a> <code>as</code> 来显式执行。</p>
<p>自动强转最初是在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md">RFC 401</a> 中定义的，并在[ RFC 1558] 中进行了扩展。</p>
<h2><a class="header" href="#coercion-sites" id="coercion-sites">Coercion sites</a></h2>
<h2><a class="header" href="#自动强转点" id="自动强转点">自动强转点</a></h2>
<p>自动强转只能发生在程序中的某些自动强转点(coercion sites)上；典型的位置是那些所需的类型是显式给出了的地方，或者是那些可以从给出的显式类型传播推导(be derived by propagation)出所需的类型（注意这里不是类型推断）的地方。可能的强转点有：</p>
<ul>
<li>
<p><code>let</code>语句中显式给出了类型。</p>
<p>例如，下面例子中 <code>&amp;mut 42</code> 自动强转成 <code>&amp;i8</code> 类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let _: &amp;i8 = &amp;mut 42; // 译者注释：`&amp;i8` 是显示给出的所需类型
<span class="boring">}
</span></code></pre></pre>
</li>
<li>
<p>静态(<code>static</code>)项和常量(<code>const</code>)项声明（类似于 <code>let</code>语句）。</p>
</li>
<li>
<p>函数调用的参数</p>
<p>被强制的值是实参(actual parameter)，它的类型被自动强转为形参(formal parameter)的类型。</p>
<p>例如，下面例子中 <code>&amp;mut 42</code> 自动强转成 <code>&amp;i8</code> 类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">fn bar(_: &amp;i8) { }

fn main() {
    bar(&amp;mut 42);
}
</code></pre></pre>
<p>对于方法调用，接受者（<code>self</code>参数）只能使用<a href="type-coercions.html#unsized-coercions">非固定尺寸类型自动强转(unsized coercion)</a>。</p>
</li>
<li>
<p>实例化结构体、联合体或枚举变体的字段。</p>
<p>例如，下面例子中 <code>&amp;mut 42</code> 自动强转成 <code>&amp;i8</code> 类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">struct Foo&lt;'a&gt; { x: &amp;'a i8 }

fn main() {
    Foo { x: &amp;mut 42 };
}
</code></pre></pre>
</li>
<li>
<p>函数结果—块中的最终表达式或者 <code>return</code>语句中的任何表达式。</p>
<p>例如，下面例子中 <code>x</code> 将自动强转成 <code>&amp;dyn Display</code> 类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::fmt::Display;
fn foo(x: &amp;u32) -&gt; &amp;dyn Display {
    x
}
<span class="boring">}
</span></code></pre></pre>
</li>
</ul>
<p>如果一在自动强转点中的表达式是自动强转传播型表达式(coercion-propagating expression)，那么该表达式中的对应子表达式也是自动强转点。传播从这些新的自动强转点开始递归。传播表达式(propagating expressions)及其相关子表达式有：</p>
<ul>
<li>
<p>数组字面量，其数组的类型为 <code>[U; n]</code>。数组字面量中的每个子表达式都是自动强转到类型 <code>U</code> 的自动强转点。</p>
</li>
<li>
<p>重复句法声明的数组字面量，其数组的类型为 <code>[U; n]</code>。重复子表达式是用于自动强转到类型 <code>U</code> 的自动强转点。</p>
</li>
<li>
<p>元组，其中如果元组是自动强转到类型 <code>(U_0, U_1, ..., U_n)</code> 的强转点，则每个子表达式都是相应类型的自动强转点，比如第0个子表达式是到类型 <code>U_0</code>的 自动强转点。</p>
</li>
<li>
<p>圆括号括起来的子表达式（<code>(e)</code>）：如果整个括号表达式的类型为 <code>U</code>，则子表达式 <code>e</code> 是自动强转到类型 <code>U</code> 的自动强转点。</p>
</li>
<li>
<p>块：如果块的类型是 <code>U</code>，那么块中的最后一个表达式（如果它不是以分号结尾的）就是一个自动强转到类型 <code>U</code> 的自动强转点。这里的块包括作为控制流语句的一部分的条件分支代码块，比如 <code>if</code>/<code>else</code>，当然前提是这些块的返回需要有一个已知的类型。</p>
</li>
</ul>
<h2><a class="header" href="#coercion-types" id="coercion-types">Coercion types</a></h2>
<h2><a class="header" href="#自动强转类型" id="自动强转类型">自动强转类型</a></h2>
<p>自动强转允许发生在下列类型之间：</p>
<ul>
<li>
<p><code>T</code> 到 <code>U</code> 如果 <code>T</code> 是 <code>U</code> 的一个<a href="subtyping.html">子类型</a> (<em>反射性场景(reflexive case)</em>)</p>
</li>
<li>
<p><code>T_1</code> 到 <code>T_3</code> 当 <code>T_1</code> 可自动强转到 <code>T_2</code> 同时 <code>T_2</code> 又能自动强转到 <code>T_3</code> (<em>传递性场景(transitive case)</em>)</p>
<p>注意这个还没有得到完全支持。</p>
</li>
<li>
<p><code>&amp;mut T</code> 到 <code>&amp;T</code></p>
</li>
<li>
<p><code>*mut T</code> 到 <code>*const T</code></p>
</li>
<li>
<p><code>&amp;T</code> 到 <code>*const T</code></p>
</li>
<li>
<p><code>&amp;mut T</code> 到 <code>*mut T</code></p>
</li>
<li>
<p><code>&amp;T</code> 或 <code>&amp;mut T</code> 到 <code>&amp;U</code> 如果 <code>T</code> 实现了 <code>Deref&lt;Target = U&gt;</code>。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">use std::ops::Deref;

struct CharContainer {
    value: char,
}

impl Deref for CharContainer {
    type Target = char;

    fn deref&lt;'a&gt;(&amp;'a self) -&gt; &amp;'a char {
        &amp;self.value
    }
}

fn foo(arg: &amp;char) {}

fn main() {
    let x = &amp;mut CharContainer { value: 'y' };
    foo(x); //&amp;mut CharContainer 自动强转成 &amp;char.
}
</code></pre></pre>
</li>
<li>
<p><code>&amp;mut T</code> 到 <code>&amp;mut U</code> 如果 <code>T</code> 实现了 <code>DerefMut&lt;Target = U&gt;</code>.</p>
</li>
<li>
<p>TyCtor(<code>T</code>) 到 TyCtor(<code>U</code>)，其中 TyCtor(<code>T</code>) 是下列之一<sup class="footnote-reference"><a href="#译注1">1</a></sup></p>
<ul>
<li><code>&amp;T</code></li>
<li><code>&amp;mut T</code></li>
<li><code>*const T</code></li>
<li><code>*mut T</code></li>
<li><code>Box&lt;T&gt;</code></li>
</ul>
<p>并且 <code>U</code> 能够通过<a href="type-coercions.html#unsized-coercions">非固定尺寸类型自动强转</a>得到。</p>
<!--将来，coerce_inner 会被递归扩展到元组和结构体上。此外从子 trait 到父类trait 的自动强转也会被加进来，更多细节请参见 [RFC 401] 。-->
</li>
<li>
<p>非捕获闭包(Non capturing closures)到函数指针(<code>fn</code> pointers)</p>
</li>
<li>
<p><code>!</code> 到任意 <code>T</code></p>
</li>
</ul>
<h3><a class="header" href="#unsized-coercions" id="unsized-coercions">Unsized Coercions</a></h3>
<h3><a class="header" href="#非固定尺寸类型自动强转" id="非固定尺寸类型自动强转">非固定尺寸类型自动强转</a></h3>
<p>下列自动强转被称为非固定尺寸类型自动强转(<code>unsized coercions</code>)，因为它们与将固定尺寸类型(sized types)转换为非固定尺寸类型(unsized types)有关，并且在一些其他自动强转不允许的情况（也就是上面罗列的情况之外的情况）下允许使用。也就是说它们可以发生在任何自动强转发生的地方。</p>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Unsize.html"><code>Unsize</code></a> 和 <a href="https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html"><code>CoerceUnsized</code></a> 这两个 trait 被用来协助这种转换的发生，并公开给标准库来使用。以下自动强转方式是内置的，并且，如果 <code>T</code> 可以用其中任一方式自动强转成 <code>U</code>，那么就会为 <code>T</code> 提供一个 <code>Unsize&lt;U&gt;</code> 的内置实现：</p>
<ul>
<li>
<p><code>[T; n]</code> 到 <code>[T]</code>.</p>
</li>
<li>
<p><code>T</code> 到 <code>dyn U</code>, 当 <code>T</code> 实现 <code>U + Sized</code>, 并且 <code>U</code> 是<a href="items/traits.html#object-safety">对象安全的</a>时。</p>
</li>
<li>
<p><code>Foo&lt;..., T, ...&gt;</code> 到 <code>Foo&lt;..., U, ...&gt;</code>, 当：</p>
<ul>
<li><code>Foo</code> 是一个结构体。</li>
<li><code>T</code> 实现了 <code>Unsize&lt;U&gt;</code>。</li>
<li><code>Foo</code> 的最后一个字段是和 <code>T</code> 相关的类型。</li>
<li>如果这最后一个字段是类型 <code>Bar&lt;T&gt;</code>，那么 <code>Bar&lt;T&gt;</code> 实现了 <code>Unsized&lt;Bar&lt;U&gt;&gt;</code>。</li>
<li><code>T</code> 不是任何其他字段的类型的一部分。</li>
</ul>
</li>
</ul>
<p>此外，当 <code>T</code> 实现了 <code>Unsize&lt;U&gt;</code> 或 <code>CoerceUnsized&lt;Foo&lt;U&gt;&gt;</code> 时，类型 <code>Foo&lt;T&gt;</code> 可以实现 <code>CoerceUnsized&lt;Foo&lt;U&gt;&gt;</code>。这就允许 <code>Foo&lt;T&gt;</code> 提供一个到 <code>Foo&lt;U&gt;</code> 的非固定尺寸类型自动强转。</p>
<blockquote>
<p>注：虽然非固定尺寸类型自动强转的定义及其实现已经稳定下来，但 <a href="https://doc.rust-lang.org/std/marker/trait.Unsize.html"><code>Unsize</code></a> 和 <a href="https://doc.rust-lang.org/std/ops/trait.CoerceUnsized.html"><code>CoerceUnsized</code></a> 这两个 trait 本身还没稳定下来，因此还不能直接用于稳定版的 Rust。</p>
</blockquote>
<h2><a class="header" href="#least-upper-bound-coercions" id="least-upper-bound-coercions">Least upper bound coercions</a></h2>
<h2><a class="header" href="#最小上界自动强转" id="最小上界自动强转">最小上界自动强转</a></h2>
<p>在某些上下文中，编译器必须将多个类型强制在一起，以尝试找到最通用的类型。这被称为“最小上界(Least Upper Bound,简称 LUB)”自动强转。LUB自动强转只在以下情况中使用：</p>
<ul>
<li>为一系列的 if分支查找共同的类型。</li>
<li>为一系列的匹配臂查找共同的类型。</li>
<li>为数组元素查找共同的类型。</li>
<li>为带有多个返回项语句的闭包的返回类型查找共同的类型。</li>
<li>检查带有多个返回语句的函数的返回类型。</li>
</ul>
<p>在这每种情况下，都有一组类型 <code>T0..Tn</code> 被共同自动强转到某个未知的目标类型 <code>T_t</code>，注意开始时 <code>T_t</code> 是未知的。LUB 自动强转的计算过程是不断迭代的。首先把目标类型 <code>T_t</code> 定为从类型 <code>T0</code> 开始。对于每一种新类型 <code>Ti</code>，考虑如下步骤是否成立：</p>
<ul>
<li>如果 <code>Ti</code> 可以自动强转为当前目标类型 <code>T_t</code>，则不做任何更改。 </li>
<li>否则，检查 <code>T_t</code> 是否可以被自动强转为 <code>Ti</code>；如果是这样，<code>T_t</code> 就改为 <code>Ti</code>。（此检查还取决于到目前为止所考虑的所有源表达式是否带有隐式自动强转。）</li>
<li>如果不是，尝试计算一个 <code>T_t</code> 和 <code>Ti</code> 的共同的超类型(supertype)，此超类型将成为新的目标类型。</li>
</ul>
<h3><a class="header" href="#examples-2" id="examples-2">Examples:</a></h3>
<h3><a class="header" href="#示例-4" id="示例-4">示例：</a></h3>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">let (a, b, c) = (0, 1, 2);
</span>// if分支的情况
let bar = if true {
    a
} else if false {
    b
} else {
    c
};

// 匹配臂的情况
let baw = match 42 {
    0 =&gt; a,
    1 =&gt; b,
    _ =&gt; c,
};

// 数组元素的情况
let bax = [a, b, c];

// 多个返回项语句的闭包的情况
let clo = || {
    if true {
        a
    } else if false {
        b
    } else {
        c
    }
};
let baz = clo();

// 检查带有多个返回语句的函数的情况
fn foo() -&gt; i32 {
    let (a, b, c) = (0, 1, 2);
    match 42 {
        0 =&gt; a,
        1 =&gt; b,
        _ =&gt; c,
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>在这些例子中，<code>ba*</code> 的类型可以通过 LUB自动强转找到。编译器检查 LUB自动强转在处理函数 <code>foo</code> 时，是否把 <code>a</code>，<code>b</code>，<code>c</code> 的结果转为了 <code>i32</code>。</p>
<h3><a class="header" href="#caveat" id="caveat">Caveat</a></h3>
<h3><a class="header" href="#警告" id="警告">警告</a></h3>
<p>我们这种描述显然是非正式的，但目前使文字描述更精确的工作正作为精细化 Rust 类型检查器的一般性工作的一部分正紧锣密鼓的进行中。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>TyCtor为类型构造器 type constructor 的简写。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#destructors" id="destructors">Destructors</a></h1>
<h1><a class="header" href="#析构函数" id="析构函数">析构函数</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/destructors.md">destructors.md</a><br />
commit: ed5ba7cebeab9780188005c78ca789bed73f381b <br />
本章译文最后维护日期：2021-07-11</p>
</blockquote>
<p>当一个<a href="glossary.html#initialized">初始化</a>了的<a href="variables.html">变量</a>或<a href="expressions.html#temporaries">临时变量</a>超出<a href="destructors.html#drop-scopes">作用域</a>时，其<em>析构函数(destructor)<em>将运行，或者说它将被</em>销毁(dropped)</em>。此外<a href="expressions/operator-expr.html#assignment-expressions">赋值</a>操作也会运行其左操作数的析构函数（如果它已经初始化了）。如果变量已部分初始化了，则只销毁其已初始化的字段。</p>
<p>类型 <code>T</code> 的析构函数由以下内容组成：</p>
<ol>
<li>如果有约束 <code>T: Drop</code>, 则调用 <a href="https://doc.rust-lang.org/std/ops/trait.Drop.html#tymethod.drop"><code>&lt;T as std::ops::Drop&gt;::drop</code></a></li>
<li>递归运行其所有字段的析构函数。
<ul>
<li><a href="types/struct.html">结构体(<code>struct</code>)</a>的字段按照声明顺序被销毁。</li>
<li>活动<a href="types/enum.html">枚举变体</a>的字段按声明顺序销毁。</li>
<li><a href="types/tuple.html">元组</a>中的字段按顺序销毁。</li>
<li><a href="types/array.html">数组</a>或拥有所有权的<a href="types/slice.html">切片</a>的元素的销毁顺序是从第一个元素到最后一个元素。</li>
<li><a href="types/closure.html">闭包</a>通过移动(move)语义捕获的变量的销毁顺序未明确指定。</li>
<li><a href="types/trait-object.html">trait对象</a>的销毁会运行其非具名基类(underlying type)的析构函数。</li>
<li>其他类型不会导致任何进一步的销毁动作发生。</li>
</ul>
</li>
</ol>
<p>如果析构函数必须手动运行，比如在实现自定义的智能指针时，可以使用标准库函数 <a href="https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html"><code>std::ptr::drop_in_place</code></a>。</p>
<p>举些（析构函数的）例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct PrintOnDrop(&amp;'static str);

impl Drop for PrintOnDrop {
    fn drop(&amp;mut self) {
        println!(&quot;{}&quot;, self.0);
    }
}

let mut overwritten = PrintOnDrop(&quot;当覆写时执行销毁&quot;);
overwritten = PrintOnDrop(&quot;当作用域结束时执行销毁&quot;);

let tuple = (PrintOnDrop(&quot;Tuple first&quot;), PrintOnDrop(&quot;Tuple second&quot;));

let moved;
// 没有析构函数在赋值时运行
moved = PrintOnDrop(&quot;Drops when moved&quot;);
// 这里执行销毁，但随后变量进入未初始化状态
moved;

// 未初始化不会被销毁
let uninitialized: PrintOnDrop;

// 在部分移动之后，后续销毁动作只销毁剩余字段。
let mut partial_move = (PrintOnDrop(&quot;first&quot;), PrintOnDrop(&quot;forgotten&quot;));
// 执行部分移出，只留下 `partial_move.0` 处于初始化状态
core::mem::forget(partial_move.1);
// 当 partial_move 的作用域结束时, 这里就只有第一个字段被销毁。
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#drop-scopes" id="drop-scopes">Drop scopes</a></h2>
<h2><a class="header" href="#销毁作用域" id="销毁作用域">销毁作用域</a></h2>
<p>每个变量或临时变量都与一个<em>销毁作用域(drop scope)</em><sup class="footnote-reference"><a href="#译注1">1</a></sup>相关联。当控制流离开一个销毁作用域时，与该作用域关联的所有变量都将按照其声明（对变量而言）或创建（对临时变量而言）的相反顺序销毁。</p>
<p>销毁作用域是在将 <a href="expressions/loop-expr.html#iterator-loops"><code>for</code></a>、<a href="expressions/if-expr.html#if-let-expressions"><code>if let</code></a> 和 <a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a> 这些表达式替换为等效的 <a href="expressions/match-expr.html"><code>match</code></a>表达式之后确定的。在确定销毁作用域这事儿上，对重载操作符与内置操作符不做区分<sup class="footnote-reference"><a href="#译注2">2</a></sup>，匹配模式的变量<a href="patterns.html#binding-modes">绑定方式(binding modes)</a>也不去考虑。</p>
<p>给定一个函数或闭包，存在以下的销毁作用域：</p>
<ul>
<li>整个函数</li>
<li>每个<a href="statements.html">语句</a></li>
<li>每个<a href="expressions.html">表达式</a></li>
<li>每个块，包括函数体
<ul>
<li>当在<a href="expressions/block-expr.html">块表达式</a>上时，整个块和整个块表达式的销毁作用域是相同的</li>
</ul>
</li>
<li>匹配(<code>match</code>)表达式的每条匹配臂(arm)</li>
</ul>
<p>销毁作用域相互嵌套如规则下。当同时离开多个作用域时，比如从函数返回时，变量会从内层的向层依次销毁。</p>
<ul>
<li>整个函数作用域是最外层的作用域。</li>
<li>函数体块包含在整个函数作用域内。</li>
<li>表达式语句中的表达式的父作用域是该语句的作用域。</li>
<li><a href="statements.html#let-statements"><code>let</code>语句</a>的初始化器(initializer)的父作用域是 <code>let</code>语句的作用域。</li>
<li>语句作用域的父作用域是包含该语句的块作用域。</li>
<li>匹配守卫(<code>match</code> guard)表达式的父作用域是该守卫所在的匹配臂的作用域。</li>
<li>在匹配表达式(<code>match</code> expression)里的 <code>=&gt;</code> 之后的表达式的父作用域是此表达式对应的匹配臂所在的那个作用域。</li>
<li>匹配臂的作用域的父作用域是它所在的匹配表达式(<code>match</code> expression)的作用域。</li>
<li>所有其他作用域的父作用域都是直接封闭该表达式的作用域。</li>
</ul>
<h3><a class="header" href="#scopes-of-function-parameters" id="scopes-of-function-parameters">Scopes of function parameters</a></h3>
<h3><a class="header" href="#函数参数的作用域" id="函数参数的作用域">函数参数的作用域</a></h3>
<p>所有函数参数都在整个函数体的作用域内有效，因此在对函数求值时，它们是最后被销毁的。实参会在其内部值被形参的模式绑定之后销毁。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct PrintOnDrop(&amp;'static str);
</span><span class="boring">impl Drop for PrintOnDrop {
</span><span class="boring">    fn drop(&amp;mut self) {
</span><span class="boring">        println!(&quot;drop({})&quot;, self.0);
</span><span class="boring">    }
</span><span class="boring">}
</span>// 先销毁 `y`，然后是第二个参数, 接下来是 `x`, 最后是第一个参数
fn patterns_in_parameters(
    (x, _): (PrintOnDrop, PrintOnDrop),
    (_, y): (PrintOnDrop, PrintOnDrop),
) {}

// 销毁顺序是 3 2 0 1
patterns_in_parameters(
    (PrintOnDrop(&quot;0&quot;), PrintOnDrop(&quot;1&quot;)),
    (PrintOnDrop(&quot;2&quot;), PrintOnDrop(&quot;3&quot;)),
);
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#scopes-of-local-variables" id="scopes-of-local-variables">Scopes of local variables</a></h3>
<h3><a class="header" href="#本地变量的作用域" id="本地变量的作用域">本地变量的作用域</a></h3>
<p>在 <code>let</code>语句中声明的局部变量与包含此 <code>let</code>语句的块作用域相关联。在匹配(<code>match</code>)表达式中声明的局部变量与声明它们的匹配(<code>match</code>)臂的匹配臂作用域相关联。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct PrintOnDrop(&amp;'static str);
</span><span class="boring">impl Drop for PrintOnDrop {
</span><span class="boring">    fn drop(&amp;mut self) {
</span><span class="boring">        println!(&quot;drop({})&quot;, self.0);
</span><span class="boring">    }
</span><span class="boring">}
</span>let declared_first = PrintOnDrop(&quot;在外层作用域内最后销毁&quot;);
{
    let declared_in_block = PrintOnDrop(&quot;在内层作用域内销毁&quot;);
}
let declared_last = PrintOnDrop(&quot;在外层作用域内最先销毁&quot;);
<span class="boring">}
</span></code></pre></pre>
<p>如果在一个匹配(<code>match</code>)表达式的同一个匹配臂中使用了多个模式，则毁顺序不确定。（译者注：这里译者不确定后半句翻译是否准确，这里给出原文：then an unspecified pattern will be used to determine the drop order.）</p>
<h3><a class="header" href="#temporary-scopes" id="temporary-scopes">Temporary scopes</a></h3>
<h3><a class="header" href="#临时作用域" id="临时作用域">临时作用域</a></h3>
<p>表达式的<em>临时作用域</em>用于该表达在位置上下文中求出的结果被保存进的那个临时变量的作用域。有些情况下，此表达式求出的结果会被<a href="destructors.html#constant-promotion">提升</a>，则此表达式不存在临时作用域。<sup class="footnote-reference"><a href="#译注3">3</a></sup></p>
<p>除了<a href="destructors.html#temporary-lifetime-extension">生存期扩展</a>之外，表达式的临时作用域是包含该表达式的最小作用域，它适用于以下情况之一:</p>
<ul>
<li>整个函数体。</li>
<li>一条语句。</li>
<li><a href="expressions/if-expr.html#if-expressions"><code>if</code></a>表达式、<a href="expressions/loop-expr.html#predicate-loops"><code>while</code></a>表达式 或 <a href="expressions/loop-expr.html#infinite-loops"><code>loop</code></a>表达式这三种表达式的代码体。</li>
<li><code>if</code>表达式的 <code>else</code>块。</li>
<li><code>if</code>表达式的条件表达式，<code>while</code>表达式的条件表达式，或匹配表达式中的匹配(<code>match</code>)守卫。</li>
<li>匹配臂上的表达式。</li>
<li><a href="expressions/operator-expr.html#lazy-boolean-operators">惰性布尔表达式</a>的第二操作数。</li>
</ul>
<blockquote>
<p><strong>注意</strong>：</p>
<p>在函数体的最终表达式(final expression)中创建的临时变量会在任何具名变量销毁<em>之后</em>销毁，因为这里没有更小的封闭它的临时作用域。</p>
<p>匹配表达式的<a href="glossary.html#scrutinee">检验对象</a>表达式本身不是一个临时作用域（，但它内部可以包含临时作用域），因此可以在匹配(<code>match</code>)表达式之后销毁检验对象表达式中的临时作用域。例如，<code>match 1 { ref mut z =&gt; z };</code> 中的 <code>1</code> 所在的临时变量一直存活到此语句结束。</p>
</blockquote>
<p>一些示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct PrintOnDrop(&amp;'static str);
</span><span class="boring">impl Drop for PrintOnDrop {
</span><span class="boring">    fn drop(&amp;mut self) {
</span><span class="boring">        println!(&quot;drop({})&quot;, self.0);
</span><span class="boring">    }
</span><span class="boring">}
</span>let local_var = PrintOnDrop(&quot;local var&quot;);

// 在条件表达式执行后立即销毁
if PrintOnDrop(&quot;If condition&quot;).0 == &quot;If condition&quot; {
    // 在此块的末尾处销毁
    PrintOnDrop(&quot;If body&quot;).0
} else {
    unreachable!()
};

// 在此条语句的末尾处销毁
(PrintOnDrop(&quot;first operand&quot;).0 == &quot;&quot;
// 在 ) 处销毁
|| PrintOnDrop(&quot;second operand&quot;).0 == &quot;&quot;)
// 在此表达式的末尾处销毁
|| PrintOnDrop(&quot;third operand&quot;).0 == &quot;&quot;;

// 在函数末尾处，局部变量之后销毁之后销毁
// 将下面这段更改为一个包含返回(return)表达式的语句将使临时变量在本地变量之前被删除。
// 如果把此临时变量绑定到一个变量，然后返回这个变量，也会先删除这个临时变量
match PrintOnDrop(&quot;Matched value in final expression&quot;) {
    // 在条件表达式执行后立即销毁
    _ if PrintOnDrop(&quot;guard condition&quot;).0 == &quot;&quot; =&gt; (),
    _ =&gt; (),
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#operands" id="operands">Operands</a></h3>
<h3><a class="header" href="#操作数" id="操作数">操作数</a></h3>
<p>在同一表达式中，在对其他操作数求值时，也会创建临时变量来将已求值的操作数的结果保存起来。临时变量与该操作数所属的表达式的作用域相关联。因为一旦表达式求值，临时变量就被移走了，所以销毁它们没有任何效果和意义，除非整个表达式的某一操作数出现异常，导致表达式求值失败，或提前返回，或触发了 panic。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct PrintOnDrop(&amp;'static str);
</span><span class="boring">impl Drop for PrintOnDrop {
</span><span class="boring">    fn drop(&amp;mut self) {
</span><span class="boring">        println!(&quot;drop({})&quot;, self.0);
</span><span class="boring">    }
</span><span class="boring">}
</span>loop {
    // 元组表达式未结束求值就提前返回了，所以其操作数按声明的反序销毁
    (
        PrintOnDrop(&quot;Outer tuple first&quot;),
        PrintOnDrop(&quot;Outer tuple second&quot;),
        (
            PrintOnDrop(&quot;Inner tuple first&quot;),
            PrintOnDrop(&quot;Inner tuple second&quot;),
            break,
        ),
        PrintOnDrop(&quot;Never created&quot;),
    );
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#constant-promotion" id="constant-promotion">Constant promotion</a></h3>
<h3><a class="header" href="#常量提升" id="常量提升">常量提升</a></h3>
<p>如果可以通过借用的方式将某一值表达式写入常量，并且还能通过解引用此借用的方式来解出原始写入的表达式，并且如果这种做法也不更改运行时行为，那 Rust 会将值表达式提升到静态(<code>'static</code>) slot 作用域内。也就是说，提升的表达式可以在编译时求值，这求得的值不具备<a href="interior-mutability.html">内部可变性</a>或不包含<a href="destructors.html">析构函数</a>（。这些属性是根据可能的值来确定的，例如 <code>&amp;None</code> 的类型总是 <code>&amp;'static Option&lt;_&gt;</code>，因为 <code>&amp;None</code> 的值是唯一确定的）。</p>
<h3><a class="header" href="#temporary-lifetime-extension" id="temporary-lifetime-extension">Temporary lifetime extension</a></h3>
<h3><a class="header" href="#临时生存期扩展" id="临时生存期扩展">临时生存期扩展</a></h3>
<blockquote>
<p><strong>注意</strong>：临时生存期扩展的确切规则可能还会改变。这里只描述了当前的行为表现。</p>
</blockquote>
<p><code>let</code>语句中表达式的临时作用域有时会<em>扩展</em>到包含此 <code>let</code>语句的块作用域内。根据某些句法规则，当通常的临时作用域太小时，就会这样做。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let x = &amp;mut 0;
// 通常上面存储0的临时变量（或者临时位置）到这里就会被丢弃，但这里是一直存在到块的末尾。
println!(&quot;{}&quot;, x);
<span class="boring">}
</span></code></pre></pre>
<p>如果一个借用、解引用、字段或元组索引表达式有一个扩展的临时作用域，那么它们的操作数也会同样扩展。如果索引表达式有扩展的临时作用域，那么被索引的表达式也会一并扩展。</p>
<h4><a class="header" href="#extending-based-on-patterns" id="extending-based-on-patterns">Extending based on patterns</a></h4>
<h4><a class="header" href="#基于模式的扩展" id="基于模式的扩展">基于模式的扩展</a></h4>
<p>*扩展临时作用域的模式(extending pattern)*是下面任一：</p>
<ul>
<li>绑定方式为引用或可变引用的<a href="patterns.html#identifier-patterns">标识符模式</a>。</li>
<li><a href="patterns.html#struct-patterns">结构体(<code>struct</code>)模式</a>、<a href="patterns.html#tuple-patterns">元组模式</a>、<a href="patterns.html#tuple-struct-patterns">元组结构体模式</a>或<a href="patterns.html#slice-patterns">切片模式</a>，其中它们至少有一个直接子模式是扩展临时作用域的模式。</li>
</ul>
<p>所以 <code>ref x</code>、<code>V(ref x)</code> 和 <code>[ref x, y]</code> 都是扩展临时作用域的模式，但是  <code>x</code>、<code>&amp;ref x</code> 和 <code>&amp;(ref x,)</code> 不是。</p>
<p>如果 <code>let</code>语句中的模式是扩展临时作用域的模式，那么初始化器表达式中的临时作用域将被扩展。</p>
<h4><a class="header" href="#extending-based-on-expressions" id="extending-based-on-expressions">Extending based on expressions</a></h4>
<h4><a class="header" href="#基于表达式的扩展" id="基于表达式的扩展">基于表达式的扩展</a></h4>
<p>对于带有初始化器的 let语句来说，*扩展临时作用域的表达式(extending expression)*是以下表达式之一：</p>
<ul>
<li>初始化表达式(initializer expression)。</li>
<li>扩展临时作用域的<a href="expressions/operator-expr.html#borrow-operators">借用表达式</a>的操作数。</li>
<li>扩展临时作用域的<a href="expressions/array-expr.html#array-expressions">数组</a>、<a href="expressions/operator-expr.html#type-cast-expressions">强制转换(cast)</a>、<a href="expressions/struct-expr.html">花括号括起来的结构体</a>或<a href="expressions/tuple-expr.html#tuple-expressions">元组</a>表达式的操作数。</li>
<li>任何扩展临时作用域的<a href="expressions/block-expr.html">块表达式</a>的最终表达式(final expression);</li>
</ul>
<p>因此，在 <code>&amp;mut 0</code>、<code>(&amp;1, &amp;mut 2)</code> 和 <code>Some { 0: &amp;mut 3 }</code> 中的借用表达式都是扩展临时作用域的表达式。在 <code>&amp;0 + &amp;1</code> 和一些 <code>Some(&amp;mut 0)</code> 中的借用不是：它们在句法上是函数调用表达式。</p>
<p>任何扩展了临时作用域的借用表达式的操作数的临时作用域都随此表达式的临时作用域的扩展而扩展。</p>
<h4><a class="header" href="#examples-3" id="examples-3">Examples</a></h4>
<h4><a class="header" href="#示例-5" id="示例-5">示例</a></h4>
<p>这是一些带有扩展的临时作用域的表达式：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn temp() {}
</span><span class="boring">trait Use { fn use_temp(&amp;self) -&gt; &amp;Self { self } }
</span><span class="boring">impl Use for () {}
</span>// 在这些情况下，存储 `temp()` 结果的临时变量与x在同一个作用域中。
let x = &amp;temp();
let x = &amp;temp() as &amp;dyn Send;
let x = (&amp;*&amp;temp(),);
let x = { [Some { 0: &amp;temp(), }] };
let ref x = temp();
let ref x = *&amp;temp();
<span class="boring">x;
</span><span class="boring">}
</span></code></pre></pre>
<p>下面是一些表达式没有扩展临时作用域的例子：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn temp() {}
</span><span class="boring">trait Use { fn use_temp(&amp;self) -&gt; &amp;Self { self } }
</span><span class="boring">impl Use for () {}
</span>// 在这些情况下，存储 `temp()` 结果的临时变量只存活到 let语句结束。

let x = Some(&amp;temp());         // ERROR
let x = (&amp;temp()).use_temp();  // ERROR
<span class="boring">x;
</span><span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#not-running-destructors" id="not-running-destructors">Not running destructors</a></h2>
<h2><a class="header" href="#阻断运行析构函数" id="阻断运行析构函数">阻断运行析构函数</a></h2>
<p>在 Rust 中，即便类型不是 <code>'static</code>，禁止运行析构函数也是允许的，也是安全的。<a href="https://doc.rust-lang.org/std/mem/struct.ManuallyDrop.html"><code>std::mem::ManuallyDrop</code></a> 提供了一个包装器(wrapper)来防止变量或字段被自动销毁。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>后文有时也直接简称为作用域。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">2</sup>
<p>这里说这句是因为操作符的操作数也涉及到销毁作用域范围的确定。</p>
</div>
<div class="footnote-definition" id="译注3"><sup class="footnote-definition-label">3</sup>
<p>对这句话，这里译者按自己的理解再翻译一遍：一个表达式在位置表达式上使用时会被求值，如果此时没有具名变量和此值绑定，那就会先被保存进一个临时变量里，临时作用域就是伴随这此临时变量而生成。此作用域通常在此表达式所在的语句结束时结束，但如果求出的值被通过借用绑定给具名变量，此作用域会扩展到此具名变量的作用域（后面<a href="destructors.html#temporary-lifetime-extension">生存期扩展</a>会讲到）。如果求出的值比较特殊，这个作用域还会提升到全局作用域，这就是所谓的<a href="destructors.html#constant-promotion">常量提升</a>。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#lifetime-elision" id="lifetime-elision">Lifetime elision</a></h1>
<h1><a class="header" href="#生存期类型参数省略" id="生存期类型参数省略">生存期(类型参数)省略</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/lifetime-elision.md">lifetime-elision.md</a><br />
commit: f8e76ee9368f498f7f044c719de68c7d95da9972 <br />
本章译文最后维护日期：2020-11-16</p>
</blockquote>
<p>Rust 拥有一套允许在多种位置省略生存期的规则，但前提是编译器在这些位置上能推断出合理的默认生存期。</p>
<h2><a class="header" href="#lifetime-elision-in-functions" id="lifetime-elision-in-functions">Lifetime elision in functions</a></h2>
<h2><a class="header" href="#函数上的生存期类型参数省略" id="函数上的生存期类型参数省略">函数上的生存期(类型参数)省略</a></h2>
<p>为了使常用模式使用起来更方便，可以在<a href="types/function-item.html">函数项</a>、<a href="types/function-pointer.html">函数指针</a>和<a href="types/closure.html">闭包trait</a><sup class="footnote-reference"><a href="#译注1">1</a></sup>的签名中<em>省略</em>生存期类型参数。以下规则用于推断出被省略的生存期类型参数。省略不能被推断出的生存期类型参数是错误的。占位符形式的生存期，<code>'_</code>，也可以用这一套规则来推断出。对于路径中的生存期，首选使用 <code>'_</code>。trait对象的生存期类型参数遵循不同的规则，具体<a href="lifetime-elision.html#default-trait-object-lifetimes">这里</a>讨论。</p>
<ul>
<li>参数中省略的每个生存期类型参数都会（被推断）成为一个独立的生存期类型参数。</li>
<li>如果参数中只使用了一个生存期（省略或不省略都行），则将该生存期作为<em>所有</em>省略的输出生存期类型参数。</li>
</ul>
<p>在方法签名中有另一条规则</p>
<ul>
<li>如果接受者(receiver)类型为 <code>&amp;Self</code> 或 <code>&amp;mut Self</code>，那么对 <code>Self</code> 的引用的生存期会被作为所有省略的输出生存期类型参数。</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">trait T {}
</span><span class="boring">trait ToCStr {}
</span><span class="boring">struct Thing&lt;'a&gt; {f: &amp;'a i32}
</span><span class="boring">struct Command;
</span><span class="boring">
</span><span class="boring">trait Example {
</span>fn print1(s: &amp;str);                                   // 省略
fn print2(s: &amp;'_ str);                                // 也省略
fn print3&lt;'a&gt;(s: &amp;'a str);                            // 未省略

fn debug1(lvl: usize, s: &amp;str);                       // 省略
fn debug2&lt;'a&gt;(lvl: usize, s: &amp;'a str);                // 未省略

fn substr1(s: &amp;str, until: usize) -&gt; &amp;str;            // 省略
fn substr2&lt;'a&gt;(s: &amp;'a str, until: usize) -&gt; &amp;'a str;  // 未省略

fn get_mut1(&amp;mut self) -&gt; &amp;mut dyn T;                 // 省略
fn get_mut2&lt;'a&gt;(&amp;'a mut self) -&gt; &amp;'a mut dyn T;       // 未省略

fn args1&lt;T: ToCStr&gt;(&amp;mut self, args: &amp;[T]) -&gt; &amp;mut Command;                  // 省略
fn args2&lt;'a, 'b, T: ToCStr&gt;(&amp;'a mut self, args: &amp;'b [T]) -&gt; &amp;'a mut Command; // 未省略

fn new1(buf: &amp;mut [u8]) -&gt; Thing&lt;'_&gt;;                 // 省略 - 首选的
fn new2(buf: &amp;mut [u8]) -&gt; Thing;                     // 省略
fn new3&lt;'a&gt;(buf: &amp;'a mut [u8]) -&gt; Thing&lt;'a&gt;;          // 未省略
<span class="boring">}
</span>
type FunPtr1 = fn(&amp;str) -&gt; &amp;str;                      // 省略
type FunPtr2 = for&lt;'a&gt; fn(&amp;'a str) -&gt; &amp;'a str;        // 未省略

type FunTrait1 = dyn Fn(&amp;str) -&gt; &amp;str;                // 省略
type FunTrait2 = dyn for&lt;'a&gt; Fn(&amp;'a str) -&gt; &amp;'a str;  // 未省略
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 下面的示例展示了不允许省略生存期类型参数的情况。

<span class="boring">trait Example {
</span>// 无法推断，因为没有可以推断的起始参数。
fn get_str() -&gt; &amp;str;                                 // 非法

// 无法推断，这里无法确认输出的生存期类型参数该遵从从第一个还是第二个参数的。
fn frob(s: &amp;str, t: &amp;str) -&gt; &amp;str;                    // 非法
<span class="boring">}
</span><span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#default-trait-object-lifetimes" id="default-trait-object-lifetimes">Default trait object lifetimes</a></h2>
<h2><a class="header" href="#默认的-trait对象的生存期" id="默认的-trait对象的生存期">默认的 trait对象的生存期</a></h2>
<p>假定存在于（代表） <a href="types/trait-object.html">trait对象</a>（的那个胖指针）上的生存期(assumed lifetime)类型参数称为此 trait对象的<em>默认对象生存期约束(default object lifetime bound)</em>。这些在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md">RFC 599</a> 中定义，在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md">RFC 1156</a> 中修定增补。</p>
<p>当 trait对象的生存期约束被完全省略时，会使用默认对象生存期约束来替代上面定义的生存期类型参数省略规则。但如果使用 <code>'_</code> 作为生存期约束，则该约束仍遵循上面通常的省略规则。</p>
<p>如果将 trait对象用作泛型类型的类型参数，则首先使用此容器泛型来尝试为此 trait对象推断一个约束（来替代那个假定的生存期）。</p>
<ul>
<li>如果存在来自此容器泛型的唯一约束，则该约束就为此 trait对象的默认约束</li>
<li>如果此容器泛型有多个约束，则必须指定一个约显式束为此 trait对象的默认约束</li>
</ul>
<p>如果这两个规则都不适用，则使用该 trait对象的声明时的 trait约束：</p>
<ul>
<li>如果原 trait 声明为单生命周期<em>约束</em>，则此 trait对象使用该约束作为默认约束。</li>
<li>如果 <code>'static</code> 被用做原 trait声明的任一一个生存期约束，则此 trait对象使用 <code>'static</code> 作为默认约束。</li>
<li>如果原 trait声明没有生存期约束，那么此 trait对象的生存期会在表达式中根据上下文被推断出来，在表达式之外直接用 <code>'static</code>。</li>
</ul>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 对下面的 trait 来说，...
trait Foo { }

// 这两个是等价的，就如 `Box&lt;T&gt;` 对 `T` 没有生存期约束一样
// These two are the same as Box&lt;T&gt; has no lifetime bound on T
type T1 = Box&lt;dyn Foo&gt;;  //译者注：此处的 `T1` 和 上行备注中提到的 `Box&lt;T&gt;` 都是本节规则中所说的泛型类型，即容器泛型
type T2 = Box&lt;dyn Foo + 'static&gt;;

// ...这也是等价的
impl dyn Foo {}
impl dyn Foo + 'static {}

// ...这也是等价的, 因为 `&amp;'a T` 需要 `T: 'a`
type T3&lt;'a&gt; = &amp;'a dyn Foo;
type T4&lt;'a&gt; = &amp;'a (dyn Foo + 'a);

// `std::cell::Ref&lt;'a, T&gt;` 也需要 `T: 'a`, 所以这俩也是等价的
type T5&lt;'a&gt; = std::cell::Ref&lt;'a, dyn Foo&gt;;
type T6&lt;'a&gt; = std::cell::Ref&lt;'a, dyn Foo + 'a&gt;;
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 这是一个反面示例：
<span class="boring">trait Foo { }
</span>struct TwoBounds&lt;'a, 'b, T: ?Sized + 'a + 'b&gt; {
    f1: &amp;'a i32,
    f2: &amp;'b i32,
    f3: T,
}
type T7&lt;'a, 'b&gt; = TwoBounds&lt;'a, 'b, dyn Foo&gt;;
//                                  ^^^^^^^
// 错误: 不能从上下文推导出此对象类型的生存期约束
<span class="boring">}
</span></code></pre></pre>
<p>注意，像 <code>&amp;'a Box&lt;dyn Foo&gt;</code> 这样多层包装的，只需要看最内层包装 <code>dyn Foo</code> 的那层，所以扩展后仍然为 <code>&amp;'a Box&lt;dyn Foo + 'static&gt;</code></p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// 对下面的 trait 来说，...
trait Bar&lt;'a&gt;: 'a { }

// ...这两个是等价的：
type T1&lt;'a&gt; = Box&lt;dyn Bar&lt;'a&gt;&gt;;
type T2&lt;'a&gt; = Box&lt;dyn Bar&lt;'a&gt; + 'a&gt;;

// ...这俩也是等价的:
impl&lt;'a&gt; dyn Bar&lt;'a&gt; {}
impl&lt;'a&gt; dyn Bar&lt;'a&gt; + 'a {}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#static-lifetime-elision" id="static-lifetime-elision"><code>'static</code> lifetime elision</a></h2>
<h2><a class="header" href="#静态static生存期省略" id="静态static生存期省略">静态(<code>'static</code>)生存期省略</a></h2>
<p>除非指定了显式的生存期，引用类型的<a href="items/constant-items.html">常量项</a>声明和<a href="items/static-items.html">静态项</a>声明都具有<em>隐式的</em>静态(<code>'static</code>)生存期。因此，有 <code>'static</code>生存期的常量项声明在编写时可以略去其生存期。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// STRING: &amp;'static str
const STRING: &amp;str = &quot;bitstring&quot;;

struct BitsNStrings&lt;'a&gt; {
    mybits: [u32; 2],
    mystring: &amp;'a str,
}

// BITS_N_STRINGS: BitsNStrings&lt;'static&gt;
const BITS_N_STRINGS: BitsNStrings&lt;'_&gt; = BitsNStrings {
    mybits: [1, 2],
    mystring: STRING,
};
<span class="boring">}
</span></code></pre></pre>
<p>注意，如果静态项(<code>static</code>)或常量项(<code>const</code>)包含对函数或闭包的引用，而这些函数或闭包本身也包含引用，此时编译器将首先尝试使用标准的省略规则来推断生存期类型参数。如果它不能通过通常的生存期省略规则来推断出生存期类型参数，那么它将报错。举个例子：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Foo;
</span><span class="boring">struct Bar;
</span><span class="boring">struct Baz;
</span><span class="boring">fn somefunc(a: &amp;Foo, b: &amp;Bar, c: &amp;Baz) -&gt; usize {42}
</span>// 解析为 `fn&lt;'a&gt;(&amp;'a str) -&gt; &amp;'a str`.
const RESOLVED_SINGLE: fn(&amp;str) -&gt; &amp;str = |x| x;

// 解析为 `Fn&lt;'a, 'b, 'c&gt;(&amp;'a Foo, &amp;'b Bar, &amp;'c Baz) -&gt; usize`.
const RESOLVED_MULTIPLE: &amp;dyn Fn(&amp;Foo, &amp;Bar, &amp;Baz) -&gt; usize = &amp;somefunc;
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">struct Foo;
</span><span class="boring">struct Bar;
</span><span class="boring">struct Baz;
</span><span class="boring">fn somefunc&lt;'a,'b&gt;(a: &amp;'a Foo, b: &amp;'b Bar) -&gt; &amp;'a Baz {unimplemented!()}
</span>// 没有足够的信息将返回值的生存期与参数的生命周期绑定起来，因此这是一个错误
const RESOLVED_STATIC: &amp;dyn Fn(&amp;Foo, &amp;Bar) -&gt; &amp;Baz = &amp;somefunc;
//                                            ^
// 这个函数的返回类型包含一个借用来的值，但是签名没有说明它是从参数1还是从参数2借用来的
<span class="boring">}
</span></code></pre></pre>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>指 Fn、FnMute 和 FnOnce 这三个 trait。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#special-types-and-traits" id="special-types-and-traits">Special types and traits</a></h1>
<h1><a class="header" href="#特殊类型和-trait" id="特殊类型和-trait">特殊类型和 trait</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/special-types-and-traits.md">special-types-and-traits.md</a><br />
commit: 4e138b37b49c49bc875b96b859fbe0caea5a82f3 <br />
本章译文最后维护日期：2021-07-17</p>
</blockquote>
<p><a href="https://doc.rust-lang.org/std/index.html">标准库</a>中的某些类型和 trait 在 Rust 编译器中也直接能用。本章就阐述了这些类型和 trait 的特殊特性。</p>
<h2><a class="header" href="#boxt" id="boxt"><code>Box&lt;T&gt;</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/boxed/struct.Box.html"><code>Box&lt;T&gt;</code></a> 有一些特殊的特性，Rust 目前还不允许用户定义类型时使用。</p>
<ul>
<li><code>Box&lt;T&gt;</code> 的[解引用操作符]会产生一个可从中移出值的内存位置<sup class="footnote-reference"><a href="#译注1">1</a></sup>。这（种特殊性）意味着应用在 <code>Box&lt;T&gt;</code> 上的 <code>*</code>运算符和 <code>Box&lt;T&gt;</code> 的析构函数都是语言内置的。</li>
<li><a href="items/associated-items.html#associated-functions-and-methods">方法</a>可以使用 <code>Box&lt;Self&gt;</code> 作为接受者。</li>
<li><code>Box&lt;T&gt;</code> 可以绕过<a href="items/implementations.html#trait-implementation-coherence">孤儿规则(orphan rules)</a>，与 <code>T</code> 在同一 crate 中实现同一 trait，其他泛型类型无法绕过。</li>
</ul>
<h2><a class="header" href="#rct" id="rct"><code>Rc&lt;T&gt;</code></a></h2>
<p><a href="items/associated-items.html#associated-functions-and-methods">方法</a>可以使用 <a href="https://doc.rust-lang.org/std/rc/struct.Rc.html"><code>Rc&lt;Self&gt;</code></a> 作为接受者。</p>
<h2><a class="header" href="#arct" id="arct"><code>Arc&lt;T&gt;</code></a></h2>
<p><a href="items/associated-items.html#associated-functions-and-methods">方法</a>可以使用 <a href="https://doc.rust-lang.org/std/sync/struct.Arc.html"><code>Arc&lt;Self&gt;</code></a> 作为接受者。</p>
<h2><a class="header" href="#pinp" id="pinp"><code>Pin&lt;P&gt;</code></a></h2>
<p><a href="items/associated-items.html#associated-functions-and-methods">方法</a>可以使用 <a href="https://doc.rust-lang.org/std/pin/struct.Pin.html"><code>Pin&lt;P&gt;</code></a> 作为接受者。</p>
<h2><a class="header" href="#unsafecellt" id="unsafecellt"><code>UnsafeCell&lt;T&gt;</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html"><code>std::cell::UnsafeCell&lt;T&gt;</code></a> 用于<a href="interior-mutability.html">内部可变性</a>。它确保编译器不会对此类类型执行不正确的优化。它还能确保具有内部可变类型的<a href="items/static-items.html">静态(<code>static</code>)项</a>不会被放在标记为只读的内存中。</p>
<h2><a class="header" href="#phantomdatat" id="phantomdatat"><code>PhantomData&lt;T&gt;</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/struct.PhantomData.html"><code>std::marker::PhantomData&lt;T&gt;</code></a> 是一个零尺寸零的、最小对齐量的、被认为拥有(own) <code>T</code> 的类型，这个类型存在目的是应用在确定<a href="subtyping.html#variance">型变</a>关系、<a href="https://doc.rust-lang.org/nomicon/dropck.html">销毁检查</a>和<a href="special-types-and-traits.html#auto-traits">自动trait</a> 中的。</p>
<h2><a class="header" href="#operator-traits" id="operator-traits">Operator Traits</a></h2>
<h2><a class="header" href="#运算符操作符trait" id="运算符操作符trait">运算符/操作符trait</a></h2>
<p><a href="https://doc.rust-lang.org/std/ops/index.html"><code>std::ops</code></a> 和 <a href="https://doc.rust-lang.org/std/cmp/index.html"><code>std::cmp</code></a> 中的 trait 看用于重载 Rust 的<a href="expressions/operator-expr.html">运算符/操作符</a>、<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">索引表达式</a>和<a href="expressions/call-expr.html">调用表达式</a>。</p>
<h2><a class="header" href="#deref-and-derefmut" id="deref-and-derefmut"><code>Deref</code> and <code>DerefMut</code></a></h2>
<p>除了重载一元 <code>*</code>运算符外，<a href="https://doc.rust-lang.org/std/ops/trait.Deref.html"><code>Deref</code></a> 和 <a href="https://doc.rust-lang.org/std/ops/trait.DerefMut.html"><code>DerefMut</code></a> 也用于<a href="expressions/method-call-expr.html">方法解析(method resolution)</a>和<a href="type-coercions.html#coercion-types">利用 <code>Deref</code> 达成自动强转</a>。</p>
<h2><a class="header" href="#drop" id="drop"><code>Drop</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/ops/trait.Drop.html"><code>Drop</code></a> trait 提供了一个<a href="destructors.html">析构函数</a>，每当要销毁此类型的值时就会运行它。</p>
<h2><a class="header" href="#copy" id="copy"><code>Copy</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Copy.html"><code>Copy</code></a> trait 改变实现它的类型的语义。其类型实现了 <code>Copy</code> 的值在赋值时将被复制而不是移动。</p>
<p>只能为未实现 <code>Drop</code> trait 且字段都是 <code>Copy</code> 的类型实现 <code>Copy</code>。<sup class="footnote-reference"><a href="#译注2">2</a></sup><br />
对于枚举，这意味着所有变体的所有字段都必须是 <code>Copy</code> 的。<br />
对于联合体，这意味着所有的变体都必须是 <code>Copy</code> 的。</p>
<p><code>Copy</code> 已由编译器实现给了下述类型：</p>
<ul>
<li><a href="types/numeric.html">数字类类型</a></li>
<li><code>char</code>, <code>bool</code>, 和 <a href="types/never.html"><code>!</code></a></li>
<li>由 <code>Copy</code> 类型的元素组成的<a href="types/tuple.html">元组</a></li>
<li>由 <code>Copy</code> 类型的元素组成的<a href="types/array.html">数组</a></li>
<li><a href="types/pointer.html#shared-references-">共享引用</a></li>
<li><a href="types/pointer.html#raw-pointers-const-and-mut">裸指针</a></li>
<li><a href="types/function-pointer.html">函数指针</a> 和 <a href="types/function-item.html">函数项类型</a></li>
</ul>
<h2><a class="header" href="#clone" id="clone"><code>Clone</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/clone/trait.Clone.html"><code>Clone</code></a> trait 是 <code>Copy</code> 的超类trait，所以它也需要编译器生成实现。它被编译器实现给了以下类型：</p>
<ul>
<li>实现了内置的 <code>Copy</code> trait 的类型（见上面）</li>
<li>由 <code>Clone</code> 类型的元素组成的<a href="types/tuple.html">元组</a></li>
<li>由 <code>Clone</code> 类型的元素组成的<a href="types/array.html">数组</a></li>
</ul>
<h2><a class="header" href="#send" id="send"><code>Send</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Send.html"><code>Send</code></a> trait 表明这种类型的值可以安全地从一个线程发送给另一个线程。</p>
<h2><a class="header" href="#sync" id="sync"><code>Sync</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Sync.html"><code>Sync</code></a> trait 表示在多个线程之间共享这种类型的值是安全的。必须为不可变<a href="items/static-items.html">静态(<code>static</code>)项</a>中使用的所有类型实现此 trait。</p>
<h2><a class="header" href="#auto-traits" id="auto-traits">Auto traits</a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Send.html"><code>Send</code></a>、<a href="https://doc.rust-lang.org/std/marker/trait.Sync.html"><code>Sync</code></a>、<a href="https://doc.rust-lang.org/std/marker/trait.Unpin.html"><code>Unpin</code></a>、<a href="https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html"><code>UnwindSafe</code></a> 和 <a href="https://doc.rust-lang.org/std/panic/trait.RefUnwindSafe.html"><code>RefUnwindSafe</code></a> trait 都是<em>自动trait(auto traits)</em>。自动trait 具有特殊的属性。</p>
<p>对于给定类型，如果没有为其显式实现或否定实现(negative implementation)某自动trait，那么编译器就会根据以下规则去自动此为类型实现该自动trait：</p>
<ul>
<li>如果 <code>T</code> 实现了某自动trait，那 <code>&amp;T</code>、<code>&amp;mut T</code>、<code>*const T</code>、<code>*mut T</code>、<code>[T; n]</code> 和 <code>[T]</code> 也会实现此自动trait。</li>
<li>函数项类型(function item types)和函数指针会自动实现这些自动trait。</li>
<li>如果结构体、枚举、联合体和元组它们的所有字段都实现了这些自动trait，则它们本身也会自动实现这些自动trait。</li>
<li>如果闭包捕获的所有变量的类型都实现了这些自动trait，那么闭包会自动实现这些自动trait。一个闭包通过共享引用捕获了一个 <code>T</code>，同时通过传值的方式捕获了一个 <code>U</code>，那么该闭包会自动实现 <code>&amp;T</code> 和 <code>U</code> 所共同实现的那些自动trait。</li>
</ul>
<p>对于泛型类型（上面的这些内置类型也算是建立在 <code>T</code> 上的泛型），如果泛型实现在当前已够用，则编译器不会再为其实现其他的自动trait，除非它们不满足必需的 trait约束。例如，标准库在 <code>T</code> 是 <code>Sync</code> 的地方都为 <code>&amp;T</code> 实现了 <code>Send</code>；这意味着如果 <code>T</code> 是 <code>Send</code>，而不是 <code>Sync</code>，编译器就不会为 <code>&amp;T</code> 自动实现 <code>Send</code>。</p>
<p>自动trait 也可以有否定实现，在标准库文档中表示为 <code>impl !AutoTrait for T</code>，它覆盖了自动实现。例如，<code>*mut T</code> 有一个关于 <code>Send</code> 的否定实现，所以 <code>*mut T</code> 不是 <code>Send</code> 的，即使 <code>T</code> 是。目前还没有稳下来的方法来指定其他类型的否定实现；目前否定实现只能在标准库里可以稳定使用。<sup class="footnote-reference"><a href="#译注3">3</a></sup></p>
<p>自动trait 可以作为额外的约束添加到任何 <a href="types/trait-object.html">trait对象</a>上，尽管通常我们见到的 trait对象的类型名上一般只显示一个 trait。例如，<code>Box&lt;dyn Debug + Send + UnwindSafe&gt;</code> 就是一个有效的类型。</p>
<h2><a class="header" href="#sized-1" id="sized-1"><code>Sized</code></a></h2>
<p><a href="https://doc.rust-lang.org/std/marker/trait.Sized.html"><code>Sized</code></a> trait表明这种类型的尺寸在编译时是已知的；也就是说，它不是一个<a href="dynamically-sized-types.html">动态尺寸类型</a>。
<a href="types/parameters.html">类型参数</a>和<a href="items/associated-items.html#associated-types">关联类型</a>默认是 <code>Sized</code> 的。
<code>Sized</code> 总是由编译器自动实现，而不是由<a href="items/implementations.html">实现(implementation items)</a>主动实现的。
这些隐式的 <code>Sized</code>约束可以通过指定 <code>?Sized</code>约束来放宽约束。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>这里是相对普通的借用/引用来说，普通的借用/引用对指向的内存位置不拥有所有权，所以无法从中移出值。</p>
</div>
<div class="footnote-definition" id="译注2"><sup class="footnote-definition-label">2</sup>
<p>实现 <code>Drop</code> trait 的类型只能是使用移动语义(move)的类型。</p>
</div>
<div class="footnote-definition" id="译注3"><sup class="footnote-definition-label">3</sup>
<p>标准库外使用需要打开特性 <code>#![feature(negative_impls)]</code>。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#names" id="names">Names</a></h1>
<h1><a class="header" href="#名称" id="名称">名称</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/names.md">keywords.md</a><br />
commit: a989af055ff4fd7e1212754490fff72c3f7cc1be
本章译文最后维护日期：2020-1-25</p>
</blockquote>
<p>*实体(entity)*是一种语言结构，在源程序中可以以某种方式被引用，通常是通过[路径(path)][paths]。实体包括<a href="types.html">类型</a>、<a href="items.html">程序项</a>、<a href="items/generics.html">泛型参数</a>、<a href="patterns.html">变量绑定</a>、<a href="expressions/loop-expr.html#loop-labels">循环标签</a>、<a href="tokens.html#lifetimes-and-loop-labels">生存期</a>、<a href="expressions/field-expr.html">字段</a>、<a href="attributes.html">属性</a>和各种<a href="attributes/diagnostics.html#lint-check-attributes">lints</a>。</p>
<p><em>声明(declaration)<em>是一种句法结构，它可以引入</em>名称</em>来引用实体。实体的名称在相关<a href="names/scopes.html"><em>作用域(scope)</em></a>内有效。作用域是指可以引用该名称的源码区域。</p>
<p>有些实体是在源码中<a href="names.html#explicitly-declared-entities">显式声明的</a>，有些则<a href="names.html#implicitly-declared-entities">隐式声明</a>为语言或编译器扩展的一部分。</p>
<p><a href="paths.html"><em>路径</em></a>用于引用实体，该引用的实体可以在其他的作用域内。生存期和循环标签使用一个带有前导单引号的<a href="tokens.html#lifetimes-and-loop-labels">专用语法来表达</a>。</p>
<p>名称被分隔成不同的<a href="names/namespaces.html"><em>命名空间</em></a>，这样允许不同名称空间中的实体拥有相同的名称，且不会发生冲突。</p>
<p><a href="names/name-resolution.html"><em>名称解析</em></a>是将路径、标识符和标签绑定到实体声明的编译时过程。</p>
<p>对某些名称的访问可能会受到此名称的<a href="visibility-and-privacy.html"><em>可见性</em></a>的限制。</p>
<h2><a class="header" href="#explicitly-declared-entities" id="explicitly-declared-entities">Explicitly declared entities</a></h2>
<h2><a class="header" href="#显式声明的实体" id="显式声明的实体">显式声明的实体</a></h2>
<p>在源码中显式引入名称的实体有：</p>
<ul>
<li><a href="items.html">程序项</a>:
<ul>
<li><a href="items/modules.html">模块声明</a></li>
<li><a href="items/extern-crates.html">外部crate声明</a></li>
<li><a href="items/use-declarations.html">Use声明</a></li>
<li><a href="items/functions.html">函数声明</a> 和 <a href="items/functions.html#function-parameters">函数的参数</a></li>
<li><a href="items/type-aliases.html">类型别名</a></li>
<li><a href="items/structs.html">结构体</a>、<a href="items/unions.html">联合体</a>、<a href="items/enumerations.html">枚举</a>、枚举变体声明和它们的字段</li>
<li><a href="items/constant-items.html">常量项声明</a></li>
<li><a href="items/static-items.html">静态项声明</a></li>
<li><a href="items/traits.html">trait项声明</a>和它们的<a href="items/associated-items.html">关联项</a></li>
<li><a href="items/external-blocks.html">外部块</a></li>
<li><a href="macros-by-example.html"><code>macro_rules</code>声明</a> 和 <a href="macros-by-example.html#metavariables">匹配器元变量</a></li>
<li><a href="items/implementations.html">实现</a>中的关联项</li>
</ul>
</li>
<li><a href="expressions.html">表达式</a>:
<ul>
<li><a href="expressions/closure-expr.html">闭包</a>的参数</li>
<li><a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a> 模式绑定</li>
<li><a href="expressions/loop-expr.html#iterator-loops"><code>for</code></a> 模式绑定</li>
<li><a href="expressions/if-expr.html#if-let-expressions"><code>if let</code></a> 模式绑定</li>
<li><a href="expressions/match-expr.html"><code>match</code></a> 模式绑定</li>
<li><a href="expressions/loop-expr.html#loop-labels">循环标签</a></li>
</ul>
</li>
<li><a href="items/generics.html">泛型参数</a></li>
<li><a href="trait-bounds.html#higher-ranked-trait-bounds">高阶trait约束</a></li>
<li><a href="statements.html#let-statements"><code>let</code>语句</a>中的模式绑定</li>
<li><a href="macros-by-example.html#the-macro_use-attribute"><code>macro_use</code>属性</a>可以从其他 crate 里引入宏名称。</li>
<li><a href="macros-by-example.html#path-based-scope"><code>macro_export</code>属性</a>可以为当前宏引入一个在当前 crate 的根模块下生效的别名</li>
</ul>
<p>此外，<a href="macros.html#macro-invocation">宏调用</a>和<a href="attributes.html">属性</a>可以通过扩展源代码到上述程序项之一来引入名称。</p>
<h2><a class="header" href="#implicitly-declared-entities" id="implicitly-declared-entities">Implicitly declared entities</a></h2>
<h2><a class="header" href="#隐式声明的实体" id="隐式声明的实体">隐式声明的实体</a></h2>
<p>以下实体由语言隐式定义，或由编译器选项和编译器扩展引入：</p>
<ul>
<li><a href="names/preludes.html#language-prelude">语言预导入包</a>:
<ul>
<li><a href="types/boolean.html">布尔型</a> — <code>bool</code></li>
<li><a href="types/textual.html">文本型</a> — <code>char</code> and <code>str</code></li>
<li><a href="types/numeric.html#integer-types">整型</a> — <code>i8</code>, <code>i16</code>, <code>i32</code>, <code>i64</code>, <code>i128</code>, <code>u8</code>, <code>u16</code>, <code>u32</code>, <code>u64</code>, <code>u128</code></li>
<li><a href="types/numeric.html#machine-dependent-integer-types">和机器平台相关的整型</a> — <code>usize</code> and <code>isize</code></li>
<li><a href="types/numeric.html#floating-point-types">浮点型</a> — <code>f32</code> and <code>f64</code></li>
</ul>
</li>
<li><a href="attributes.html#built-in-attributes-index">内置属性</a></li>
<li><a href="names/preludes.html#standard-library-prelude">标准库预导入包</a>里的程序项、属性和宏</li>
<li>在根模块下的<a href="names/preludes.html#extern-prelude">标准库</a>里的crate</li>
<li>通过编译器链接进的<a href="names/preludes.html#extern-prelude">外部crate</a></li>
<li><a href="attributes.html#tool-attributes">工具类属性</a></li>
<li><a href="attributes/diagnostics.html#lint-check-attributes">Lints</a> 和 <a href="attributes/diagnostics.html#tool-lint-attributes">工具类lint属性</a></li>
<li><a href="procedural-macros.html#derive-macro-helper-attributes">派生辅助属性</a>无需显示引入，就在其程序项内有效</li>
<li><a href="keywords.html#weak-keywords"><code>'static</code></a>生存期标签</li>
</ul>
<p>此外，crate 的根模块没有名称，但可以使用某些<a href="paths.html#path-qualifiers">路径限定符</a>或别名来引用。</p>
<h1><a class="header" href="#namespaces" id="namespaces">Namespaces</a></h1>
<h1><a class="header" href="#命名空间" id="命名空间">命名空间</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/names/namespaces.md">use-declarations.md</a><br />
commit: 222c426ec1464757e7477ad836d97e427dde886b <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<p><em>命名空间</em>是已声明的<a href="names/../names.html">名称</a>的逻辑分组。根据名称所指的实体类型，名称被分隔到不同的命名空间中。
名称空间允许一个名称空间中出现的名称与另一个名称空间中的相同，且不会导致冲突。</p>
<p>在命名空间中，名称被组织在不同的层次结构中，层次结构的每一层都有自己的命名实体集合。</p>
<p>程序有几个不同的命名空间，每个名称空间包含不同种类的实体。使用名称时将根据上下文来在不同的命名空间中去查找该名称的声明，<a href="names/name-resolution.html">名称解析</a>一章有讲到这些。</p>
<p>下面是一系列命名空间及其对应实体的列表：</p>
<ul>
<li>类型命名空间
<ul>
<li><a href="names/../items/modules.html">模块声明</a></li>
<li><a href="names/../items/extern-crates.html">外部crate声明</a></li>
<li><a href="names/preludes.html#extern-prelude">外部预导入包</a>中的程序项</li>
<li><a href="names/../items/structs.html">结构体</a>声明、<a href="names/../items/unions.html">联合体</a>声明、<a href="names/../items/enumerations.html">枚举</a>声明和枚举变体声明</li>
<li><a href="names/../items/traits.html">trait项声明</a></li>
<li><a href="names/../items/type-aliases.html">类型别名</a></li>
<li><a href="names/../items/associated-items.html#associated-types">关联类型声明</a></li>
<li>内置类型：<a href="names/../types/boolean.html">布尔型</a>、<a href="names/../types/numeric.html">数字型</a>和<a href="names/../types/textual.html">文本型</a></li>
<li><a href="names/../items/generics.html">泛型类型参数</a></li>
<li><a href="names/../paths.html#self-1"><code>Self</code>类型</a></li>
<li><a href="names/../attributes.html#tool-attributes">工具类属性模块</a></li>
</ul>
</li>
<li>值命名空间
<ul>
<li><a href="names/../items/functions.html">函数声明</a></li>
<li><a href="names/../items/constant-items.html">常量项声明</a></li>
<li><a href="names/../items/static-items.html">静态项声明</a></li>
<li><a href="names/../items/structs.html">结构体构造器</a></li>
<li><a href="names/../items/enumerations.html">枚举变体构造器</a></li>
<li><a href="names/../paths.html#self-1"><code>Self</code>构造器</a></li>
<li><a href="names/../items/generics.html#const-generics">泛型常量参数</a></li>
<li><a href="names/../items/associated-items.html#associated-constants">关联常量声明</a></li>
<li><a href="names/../items/associated-items.html#associated-functions-and-methods">关联函数声明</a></li>
<li>本地绑定 — <a href="names/../statements.html#let-statements"><code>let</code></a>, <a href="names/../expressions/if-expr.html#if-let-expressions"><code>if let</code></a>, <a href="names/../expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a>, <a href="names/../expressions/loop-expr.html#iterator-loops"><code>for</code></a>, <a href="names/../expressions/match-expr.html"><code>match</code></a>臂, <a href="names/../items/functions.html#function-parameters">函数参数</a>, <a href="names/../expressions/closure-expr.html">闭包参数</a></li>
<li><a href="names/../expressions/closure-expr.html">闭包</a>捕获的变量</li>
</ul>
</li>
<li>宏命名空间
<ul>
<li><a href="names/../macros-by-example.html"><code>macro_rules</code>声明</a></li>
<li><a href="names/../attributes.html#built-in-attributes-index">内置属性</a></li>
<li><a href="names/../attributes.html#tool-attributes">工具类属性</a></li>
<li><a href="names/../procedural-macros.html#function-like-procedural-macros">类函数过程宏</a></li>
<li><a href="names/../procedural-macros.html#derive-macros">派生宏</a></li>
<li><a href="names/../procedural-macros.html#derive-macro-helper-attributes">辅助派生宏</a></li>
<li><a href="names/../procedural-macros.html#attribute-macros">属性宏</a></li>
</ul>
</li>
<li>生存期命名空间
<ul>
<li><a href="names/../items/generics.html">泛型生存期参数</a></li>
</ul>
</li>
<li>标签命名空间<sup class="footnote-reference"><a href="#rustc-lifetime-shadow">1</a></sup>
<ul>
<li><a href="names/../expressions/loop-expr.html#loop-labels">循环标签</a></li>
</ul>
</li>
</ul>
<p>如何清晰地使用不同命名空间中的同名名称的示例：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// Foo 在类型命名空间中引入了一个类型，在值命名空间中引入了一个构造函数
struct Foo(u32);

// 宏`Foo`在宏命名空间中声明
macro_rules! Foo {
    () =&gt; {};
}

// 参数`f` 的类型中的 `Foo` 指向类型命名空间中的 `Foo`
// `'Foo` 引入一个生存期命名空间里的新的生存期
fn example&lt;'Foo&gt;(f: Foo) {
    // `Foo` 引用值命名空间里的 `Foo`构造器。
    let ctor = Foo;
    // `Foo` 引用宏命名空间里的 `Foo`宏。
    Foo!{}
    // `'Foo` 引入一个标签命名空间里的标签。
    'Foo: loop {
        // `'Foo` 引用 `'Foo`生存期参数, `Foo` 引用类型命名空间中的类型。
        let x: &amp;'Foo Foo;
        // `'Foo` 引用了 `'Foo`标签.
        break 'Foo;
    }
}
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#named-entities-without-a-namespace" id="named-entities-without-a-namespace">Named entities without a namespace</a></h2>
<h2><a class="header" href="#无命名空间的命名实体" id="无命名空间的命名实体">无命名空间的命名实体</a></h2>
<p>下面的实体有显式的名称，但是这些名称不属于任何特定的命名空间。</p>
<h3><a class="header" href="#fields" id="fields">Fields</a></h3>
<h3><a class="header" href="#字段" id="字段">字段</a></h3>
<p>即使结构体、枚举和联合体的字段被命名，但这些命名字段并不存在于任何显式的命名空间中。它们只能通过<a href="names/../expressions/field-expr.html">字段表达式</a>访问，该表达式只检测被访问的特定类型的字段名。</p>
<h3><a class="header" href="#use-declarations-1" id="use-declarations-1">Use declarations</a></h3>
<h3><a class="header" href="#use声明-1" id="use声明-1">use声明</a></h3>
<p><a href="names/../items/use-declarations.html">use声明</a>命名了导入到当前作用域中的实体，但 <code>use</code>项本身不属于任何特定的命名空间。相反，它可以在多个名称空间中引入别名，这取决于所导入的程序项类型。</p>
<!-- TODO: describe how `use` works on the use-declarations page, and link to it here. -->
<h2><a class="header" href="#sub-namespaces" id="sub-namespaces">Sub-namespaces</a></h2>
<h2><a class="header" href="#子命名空间" id="子命名空间">子命名空间</a></h2>
<p>宏的命名空间分为两个子命名空间：一个子命名空间用于[那种带感叹号(!)的宏][bang style macros]，另一个子命名空间用于<a href="names/../attributes.html">属性</a>。
解析属性时，此属性所影响的作用域中的任何带感叹号(!)的宏都将被忽略。
反之，解析带感叹号(!)的宏将忽略作用域中的任何属性宏。
这样可以防止一种形式的宏遮挡另一种形式的。</p>
<p>例如，<a href="names/../conditional-compilation.html#the-cfg-attribute"><code>cfg</code>属性</a>和<a href="names/../conditional-compilation.html#the-cfg-macro"><code>cfg</code>宏</a>是宏命名空间中具有相同名称的两个不同实体，但它们仍然可以在各自的上下文中使用。</p>
<p>使用 <a href="names/../items/use-declarations.html"><code>use</code>导入</a>来对另一个宏进行遮蔽处理仍然是错误的，不管它们的子命名空间是什么</p>
<div class="footnote-definition" id="rustc-lifetime-shadow"><sup class="footnote-definition-label">1</sup>
<p>目前，在同一个作用域中，标签和生命周期使用相同名称时，<code>rustc</code> 会警告出现命名重复，但编译器内部仍然会独立地区别对待它们。这是一个关于该语言可能扩展的未来兼容性警告。具体见<a href="https://github.com/rust-lang/rust/pull/24162">PR #24162</a>。</p>
</div>
<h1><a class="header" href="#scopes" id="scopes">Scopes</a></h1>
<h1><a class="header" href="#作用域" id="作用域">作用域</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/names/scopes.md">use-declarations.md</a><br />
commit: eabdf09207bf3563ae96db9d576de0758c413d5d <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<blockquote>
<p><strong>注意</strong>：这是未来本章内容扩展的占位符。</p>
</blockquote>
<h1><a class="header" href="#preludes" id="preludes">Preludes</a></h1>
<h1><a class="header" href="#预导入包" id="预导入包">预导入包</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/names/preludes.md">use-declarations.md</a><br />
commit: 0ce54e64e3c98d99862485c57087d0ab36f40ef0 <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<p><em>预导入包</em>是一组名称的集合，它会自动把这些名称导入到 crate 中的每个模块的作用域中。</p>
<p>预导入包中的那些名称不是当前模块本身的一部分，它们在<a href="names/name-resolution.html">名称解析</a>期间被隐式导入。例如，即使像 <a href="names/../../std/boxed/struct.Box.html"><code>Box</code></a> 这样在每个模块的作用域中到处使用的名称，你也不能通过 <code>self::Box</code> 来引用它，因为它不是当前模块的成员。</p>
<p>有几个不同的预导入包：</p>
<ul>
<li><a href="names/preludes.html#standard-library-prelude">标准库预导入包</a></li>
<li><a href="names/preludes.html#extern-prelude">外部预导入包</a></li>
<li><a href="names/preludes.html#language-prelude">语言预导入包</a></li>
<li><a href="names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a></li>
<li><a href="names/preludes.html#tool-prelude">工具类预导入包</a></li>
</ul>
<h2><a class="header" href="#standard-library-prelude" id="standard-library-prelude">Standard library prelude</a></h2>
<h2><a class="header" href="#标准库预导入包" id="标准库预导入包">标准库预导入包</a></h2>
<p>标准库预导入包包含了 <a href="names/../../std/prelude/index.html"><code>std::prelude::v1</code></a>模块中的名称。如果使用<a href="names/preludes.html#the-no_std-attribute"><code>no_std</code>属性</a>，那么它将使用<a href="names/../../core/prelude/index.html"><code>core::prelude::v1</code></a>模块中的名称。</p>
<h2><a class="header" href="#extern-prelude-1" id="extern-prelude-1">Extern prelude</a></h2>
<h2><a class="header" href="#外部预导入包-1" id="外部预导入包-1">外部预导入包</a></h2>
<p>在根模块中使用 <a href="names/../items/extern-crates.html"><code>extern crate</code></a> 导入的外部crate 或直接给编译器提供的的外部crate（也就是在 <code>rustc</code>命令下使用 <code>--extern</code>命令行参数选项）会被添加到<em>外部预导入包</em>中。如果使用 <code>extern crate orig_name as new_name</code> 这类别名导入，则符号 <code>new_name</code> 将被添加到此预导入包。</p>
<p><a href="names/../../core/index.html"><code>core</code></a> crate 总是会被添加到外部预导入包中。只要 <a href="names/preludes.html#the-no_std-attribute"><code>no_std</code>属性</a>没有在 crate根模块中指定，那么<a href="names/../../std/index.html"><code>std</code></a> crate 就会被添加进来</p>
<blockquote>
<p><strong>版本差异</strong>：在 2015 版中，在外部预导入包中的 crate 不能通过 <a href="names/../items/use-declarations.html">use声明</a>来直接引用，因此通常标准做法是用 <code>extern crate</code> 将那它们纳入到当前作用域。</p>
<p>从 2018 版开始， <a href="names/../items/use-declarations.html">use声明</a>可以直接引用外部预导入包里的 crate，所以再在代码里使用 <code>extern crate</code> 就会被认为是不规范的。</p>
</blockquote>
<blockquote>
<p><strong>注意</strong>: 随 <code>rustc</code> 一起引入的 crate，如 <a href="names/../../alloc/index.html"><code>alloc</code></a> 和 <a href="names/../../test/index.html"><code>test</code></a>，在使用 Cargo 时不会自动被包含在 <code>--extern</code> 命令行参数选项中。即使在 2018 版中，也必须通过外部crate(<code>extern crate</code>)声明来把它们引入到当前作用域内。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>extern crate alloc;
use alloc::rc::Rc;
<span class="boring">}
</span></code></pre></pre>
<p>Cargo却会将 <code>proc_macro</code> 带入到编译类型为 proc-macro 的 crate 的外部预导入包中</p>
</blockquote>
<!--
查看 https://github.com/rust-lang/rust/issues/57288 以了解更多关于 alloc/test 的限制。
-->
<h3><a class="header" href="#the-no_std-attribute" id="the-no_std-attribute">The <code>no_std</code> attribute</a></h3>
<h3><a class="header" href="#no_std属性" id="no_std属性"><code>no_std</code>属性</a></h3>
<p>默认情况下，标准库自动包含在 crate根模块中。在 <a href="names/../../std/index.html"><code>std</code></a> crate 被添加到根模块中的同时，还会隐式生效一个 <a href="names/../macros-by-example.html#the-macro_use-attribute"><code>macro_use</code>属性</a>，它将所有从 <code>std</code> 中导出的宏放入到<a href="names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a>中。默认情况下，<a href="names/../../core/index.html"><code>core</code></a> 和 <a href="names/../../std/index.html"><code>std</code></a> 都被添加到<a href="names/preludes.html#extern-prelude">外部预导入包</a>中。<a href="names/preludes.html#standard-library-prelude">标准库预导入包</a>包含了 <a href="names/../../std/prelude/index.html"><code>std::prelude::v1</code></a>模块中的所有内容。</p>
<p>*<code>no_std</code><a href="names/../attributes.html">属性</a>*可以应用在 crate 级别上，用来防止 <a href="names/../../std/index.html"><code>std</code></a> crate 被自动添加到相关作用域内。此属性作了如下三件事：</p>
<ul>
<li>阻止 <code>std</code> crate 被添加进<a href="names/preludes.html#extern-prelude">外部预导入包</a>。</li>
<li>使用<a href="names/preludes.html#standard-library-prelude">标准库预导入包</a>中的 <a href="names/../../core/prelude/index.html"><code>core::prelude::v1</code></a> 来替代默认情况下导入的 <a href="names/../../std/prelude/index.html"><code>std::prelude::v1</code></a>。</li>
<li>使用 <a href="names/../../core/index.html"><code>core</code></a> crate 替代 <a href="names/../../std/index.html"><code>std</code></a> crate 来注入到当前 crate 的根模块中，同时把 <code>core</code> crate下的所有宏导入到 <a href="names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a>中。</li>
</ul>
<blockquote>
<p><strong>注意</strong>：当 crate 的目标平台不支持标准库或者故意不使用标准库的功能时，使用核心预导入包而不是标准预导入包是很有用的。此时没有导入的标准库的那些功能主要是动态内存分配（例如：<code>Box</code>和' <code>Vec</code>）和文件，以及网络功能（例如：<code>std::fs</code> 和 <code>std::io</code>）。</p>
</blockquote>
<div class="warning">
<p>警告：使用 <code>no_std</code> 并不会阻止标准库被链接进来。使用 <code>extern crate std;</code> 将 <code>std</code> crate 导入仍然有效，相关的依赖项也可以被正常链接进来。</p>
</div>
<h2><a class="header" href="#language-prelude" id="language-prelude">Language prelude</a></h2>
<h2><a class="header" href="#语言预导入包" id="语言预导入包">语言预导入包</a></h2>
<p>语言预导入包包括语言内置的类型名称和属性名称。语言预导入包总是在当前作用域内有效的。它包括以下内容：</p>
<ul>
<li><a href="names/namespaces.html">类型命名空间</a>
<ul>
<li><a href="names/../types/boolean.html">布尔型</a> — <code>bool</code></li>
<li><a href="names/../types/textual.html">文本型</a> — <code>char</code> 和 <code>str</code></li>
<li><a href="names/../types/numeric.html#integer-types">整型</a> — <code>i8</code>, <code>i16</code>, <code>i32</code>, <code>i64</code>, <code>i128</code>, <code>u8</code>, <code>u16</code>, <code>u32</code>, <code>u64</code>, <code>u128</code></li>
<li><a href="names/../types/numeric.html#machine-dependent-integer-types">和机器平台相关的整型</a> — <code>usize</code> 和 <code>isize</code></li>
<li><a href="names/../types/numeric.html#floating-point-types">浮点型</a> — <code>f32</code> 和 <code>f64</code></li>
</ul>
</li>
<li><a href="names/namespaces.html">宏命名空间</a>
<ul>
<li><a href="names/../attributes.html#built-in-attributes-index">内置属性</a></li>
</ul>
</li>
</ul>
<h2><a class="header" href="#macro_use-prelude" id="macro_use-prelude"><code>macro_use</code> prelude</a></h2>
<h2><a class="header" href="#macro_use预导入包" id="macro_use预导入包"><code>macro_use</code>预导入包</a></h2>
<p><code>macro_use</code>预导入包包含了外部crate 中的宏，这些宏是通过在当前文档源码内部的 <a href="names/../items/extern-crates.html"><code>extern crate</code></a> 声明语句上应用 <a href="names/../macros-by-example.html#the-macro_use-attribute"><code>macro_use</code>属性</a>来导入此声明中的 crate 内部的宏。</p>
<h2><a class="header" href="#tool-prelude" id="tool-prelude">Tool prelude</a></h2>
<h2><a class="header" href="#工具类预导入包" id="工具类预导入包">工具类预导入包</a></h2>
<p>工具类预导入包包含了在<a href="names/namespaces.html">类型命名空间</a>中声明的外部工具的工具名称。请参阅<a href="names/../attributes.html#tool-attributes">工具类属性</a>一节，以了解更多细节。</p>
<h2><a class="header" href="#the-no_implicit_prelude-attribute" id="the-no_implicit_prelude-attribute">The <code>no_implicit_prelude</code> attribute</a></h2>
<h2><a class="header" href="#no_implicit_prelude属性" id="no_implicit_prelude属性"><code>no_implicit_prelude</code>属性</a></h2>
<p>*<code>no_implicit_prelude</code><a href="names/../attributes.html">属性</a>*可以应用在 crate级别或模块上，用以指示它不应该自动将<a href="names/preludes.html#standard-library-prelude">标准库预导入包</a>、<a href="names/preludes.html#extern-prelude">外部预导入包</a>或<a href="names/preludes.html#tool-prelude">工具类预导入包</a>引入到当前模块或其任何子模块的作用域中。</p>
<p>此属性不影响<a href="names/preludes.html#language-prelude">语言预导入包</a>。</p>
<blockquote>
<p><strong>版本差异</strong>: 在 2015版中，<code>no_implicit_prelude</code>属性不会影响<a href="names/preludes.html#macro_use-prelude"><code>macro_use</code>预导入包</a>，从标准库导出的所有宏仍然包含在 <code>macro_use</code>预导入包中。从 2018版开始，它也会禁止 <code>macro_use</code>预导入包生效。</p>
</blockquote>
<h1><a class="header" href="#paths" id="paths">Paths</a></h1>
<h1><a class="header" href="#路径" id="路径">路径</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/paths.md">paths.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<p><em>路径</em>是一个或多个由命名空间<span class="parenthetical">限定符(<code>::</code>)</span><em>逻辑</em>分隔的路径段(path segments)组成的序列（译者注：如果只有一个段的话，<code>::</code> 不是必须的）。如果路径仅由一个路径段组成，则它引用局部控制域(control scope)内的<a href="items.html">程序项</a>或<a href="variables.html">变量</a>。如果路径包含多个路径段，则总是引用程序项。</p>
<p>仅由标识符段组成的简单路径(simple paths)的两个示例：</p>
<!-- ignore: syntax fragment -->
<pre><code class="language-rust ignore">x;
x::y::z;net
</code></pre>
<h2><a class="header" href="#types-of-paths" id="types-of-paths">Types of paths</a></h2>
<h2><a class="header" href="#路径分类" id="路径分类">路径分类</a></h2>
<h3><a class="header" href="#simple-paths" id="simple-paths">Simple Paths</a></h3>
<h3><a class="header" href="#简单路径" id="简单路径">简单路径</a></h3>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>SimplePath</em> :<br />
   <code>::</code><sup>?</sup> <em>SimplePathSegment</em> (<code>::</code> <em>SimplePathSegment</em>)<sup>*</sup></p>
<p><em>SimplePathSegment</em> :<br />
   <a href="identifiers.html">IDENTIFIER</a> | <code>super</code> | <code>self</code> | <code>crate</code> | <code>$crate</code></p>
</blockquote>
<p>简单路径可用于<a href="visibility-and-privacy.html">可见性</a>标记、<a href="attributes.html">属性</a>、<a href="macros-by-example.html">宏</a>和 <a href="items/use-declarations.html"><code>use</code></a>程序项中。示例：</p>
<pre><pre class="playground"><code class="language-rustnet edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>use std::io::{self, Write};
mod m {
    #[clippy::cyclomatic_complexity = &quot;0&quot;]
    pub (in super) fn f1() {}
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#paths-in-expressions" id="paths-in-expressions">Paths in expressions</a></h3>
<h3><a class="header" href="#表达式中的路径" id="表达式中的路径">表达式中的路径</a></h3>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>PathInExpression</em> :\net
   <code>::</code><sup>?</sup> <em>PathExprSegment</em> (<code>::</code> <em>PathExprSegment</em>)<sup>*</sup></p>
<p><em>PathExprSegment</em> :<br />
   <em>PathIdentSegment</em> (<code>::</code> <em>GenericArgs</em>)<sup>?</sup></p>
<p><em>PathIdentSegment</em> :<br />
   <a href="identifiers.html">IDENTIFIER</a> | <code>super</code> | <code>self</code> | <code>Self</code> | <code>crate</code> | <code>$crate</code></p>
<p><em>GenericArgs</em> :<br />
      <code>&lt;</code> <code>&gt;</code><br />
   | <code>&lt;</code> ( <em>GenericArg</em> <code>,</code> )<sup>*</sup> <em>GenericArg</em> <code>,</code><sup>?</sup> <code>&gt;</code></p>
<p><em>GenericArg</em> :\net
   <a href="trait-bounds.html"><em>Lifetime</em></a> | <a href="types.html#type-expressions"><em>Type</em></a> | <em>GenericArgsConst</em> | <em>GenericArgsBinding</em></p>
<p><em>GenericArgsConst</em> :<br />
      <a href="expressions/block-expr.html"><em>BlockExpression</em></a><br />
   | <a href="expressions/literal-expr.html"><em>LiteralExpression</em></a><br />
   | <code>-</code> <a href="expressions/literal-expr.html"><em>LiteralExpression</em></a><br />
   | <a href="paths.html#simple-paths"><em>SimplePathSegment</em></a></p>
<p><em>GenericArgsBinding</em> :<br />
   <a href="identifiers.html">IDENTIFIER</a> <code>=</code> <a href="types.html#type-expressions"><em>Type</em></a></p>
</blockquote>
<p>表达式中的路径允许指定带有泛型参数的路径。它们在各种<a href="expressions.html">表达式</a>和<a href="patterns.html">模式</a>中都有使用。</p>
<p>token <code>::</code> 必须在泛型参数的左尖括号（<code>&lt;</code>）的前面，以避免和小于号操作符产生混淆。这就是俗称的“涡轮鱼(turbofish)”句法。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>(0..10).collect::&lt;Vec&lt;_&gt;&gt;();net
Vec::&lt;u8&gt;::with_capacity(1024);
<span class="boring">}
</span></code></pre></pre>
<p>泛型参数的顺序被限制为生存期参数，然后是类型参数，然后是常量参数，再后是相应的约束。</p>
<p>常量实参必须用花括号括起来，除非它们是<a href="expressions/literal-expr.html">字面量</a>或单段路径。</p>
<h2><a class="header" href="#qualified-paths" id="qualified-paths">Qualified paths</a></h2>
<h2><a class="header" href="#限定性路径" id="限定性路径">限定性路径</a></h2>
<blockquote>
<p><strong><sup>句法</sup></strong><br />
<em>QualifiedPathInExpression</em> :<br />
   <em>QualifiedPathType</em> (<code>::</code> <em>PathExprSegment</em>)<sup>+</sup></p>
<p><em>QualifiedPathType</em> :<br />
   <code>&lt;</code> <a href="types.html#type-expressions"><em>Type</em></a> (<code>as</code> <em>TypePath</em>)? <code>&gt;</code></p>
<p><em>QualifiedPathInType</em> :<br />
   <em>QualifiedPathType</em> (<code>::</code> <em>TypePathSegment</em>)<sup>+</sup></p>
</blockquote>
<p>完全限定性路径可以用来为 <a href="items/implementations.html#trait-implementations">trait实现(trait implementations)</a>消除路径歧义，也可以用来指定<a href="paths.html#canonical-paths">规范路径</a>。用在指定具体类型时，它支持使用如下所示的类型句法：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>struct S;
impl S {
    fn f() { println!(&quot;S&quot;); }
}
trait T1 {
    fn f() { println!(&quot;T1 f&quot;); }
}
impl T1 for S {}
trait T2 {net
    fn f() { println!(&quot;T2 f&quot;); }
}net
&gt; _TypePath_ :\
&gt; &amp;nbsp;&amp;nbsp; `::`&lt;sup&gt;?&lt;/sup&gt; _TypePathSegment_ (`::` _TypePathSegment_)&lt;sup&gt;\*&lt;/sup&gt;
&gt;
&gt; _TypePathSegment_ :\
&gt; &amp;nbsp;&amp;nbsp; _PathIdentSegment_ `::`&lt;sup&gt;?&lt;/sup&gt; ([_GenericArgs_] | _TypePathFn_)&lt;sup&gt;?&lt;/sup&gt;
&gt;
&gt; _TypePathFn_ :\
&gt; `(` _TypePathFnInputs_&lt;sup&gt;?&lt;/sup&gt; `)` (`-&gt;` [_Type_])&lt;sup&gt;?&lt;/sup&gt;
&gt;
&gt; _TypePathFnInputs_ :\
&gt; [_Type_] (`,` [_Type_])&lt;sup&gt;\*&lt;/sup&gt; `,`&lt;sup&gt;?&lt;/sup&gt;

类型路径用于类型定义、trait约束(trait bound)、类型参数约束，以及限定性路径。

尽管在泛型参数之前允许使用 token `::`，但它不是必需的，因为在类型路径中不存在像 _PathInExpression_ 句法中那样的歧义。

```rust
<span class="boring">mod ops {
</span><span class="boring">    pub struct Range&lt;T&gt; {f1: T}
</span><span class="boring">    pub trait Index&lt;T&gt; {}
</span><span class="boring">    pub struct Example&lt;'a&gt; {f1: &amp;'a i32}
</span><span class="boring">}
</span><span class="boring">struct S;
</span>impl ops::Index&lt;ops::Range&lt;usize&gt;&gt; for S { /*...*/ }
fn i&lt;'a&gt;() -&gt; impl Iterator&lt;Item = ops::Example&lt;'a&gt;&gt; {
    // ...net
<span class="boring">   const EXAMPLE: Vec&lt;ops::Example&lt;'static&gt;&gt; = Vec::new();
</span><span class="boring">   EXAMPLE.into_iter()
</span>}
type G = std::boxed::Box&lt;dyn std::ops::FnOnce(isize) -&gt; isize&gt;;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#path-qualifiers" id="path-qualifiers">Path qualifiers</a></h2>
<h2><a class="header" href="#路径限定符" id="路径限定符">路径限定符</a></h2>
<p>路径可以被各种能改变其解析方式的前导限定符限定。</p>
<h3><a class="header" href="#" id=""><code>::</code></a></h3>
<p>以 <code>::</code> 开头的路径被认为是全局路径，其中的路径首段在不同的版本中的解析方式有所不同。但路径中的每个标识符都必须解析为一个程序项。</p>
<blockquote>
<p><strong>版本差异</strong>: 在2015版中，标识符解析从“create 根模块(crate root)”（2018版中表示为 <code>crate::</code>）开始，“create 根模块(crate root)”中包含了一系列不同的程序项，包括外部crate、默认create（如 <code>std</code> 或 <code>core</code>），以及 crate下的各种顶层程序项（包括 <code>use</code>导入）。</p>
<p>从 2018 版开始，以 <code>::</code> 开头的路径被解析为<a href="names/preludes.html#extern-prelude">外部预导入包</a>中的一个 crate。也就是说，其后必须跟一个 crate的名称。</p>
</blockquote>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub fn foo() {
    // 在 2018版中，这种访问 `std` 的方法是通过外部预导入包的形式达到的
    // 在 2015版中, 这种访问 `std` 的方法是通过crate根的形式达到的
    let now = ::std::time::Instant::now();
    println!(&quot;{:?}&quot;, now);
}
<span class="boring">}
</span></code></pre></pre>
<pre><pre class="playground"><code class="language-rust edition2015">// 2015 Edition
mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        ::a::foo(); // 调用 `a`'的 foo 函数
        // 在 Rust 2018 中, `::a` 会被解析为 crate `a`.
    }
}
<span class="boring">fn main() {}
</span></code></pre></pre>
<h3><a class="header" href="#self" id="self"><code>self</code></a></h3>
<p><code>self</code> 表示路径是相对于当前模块的路径。<code>self</code> 仅可以用作路径的首段，不能有前置 <code>::</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">fn foo() {}
fn bar() {
    self::foo();
}
<span class="boring">fn main() {}
</span></code></pre></pre>
<h3><a class="header" href="#self-1" id="self-1"><code>Self</code></a></h3>
<p><code>Self</code>（首字母大写）用于指代 <a href="items/traits.html">trait</a> 和<a href="items/implementations.html">实现</a>中的类型。</p>
<p><code>Self</code> 仅可以用作路径的首段，不能有前置 <code>::</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>trait T {
    type Item;
    const C: i32;
    // `Self` 将是实现 `T` 的任何类型。
    fn new() -&gt; Self;
    // `Self::Item` 将是实现中指定的类型的别名。
    fn f(&amp;self) -&gt; Self::Item;
}
struct S;
impl T for S {
    type Item = i32;
    const C: i32 = 9;
    fn new() -&gt; Self {           // `Self` 是类型 `S`.
        S
    }
    fn f(&amp;self) -&gt; Self::Item {  // `Self::Item` 是类型 `i32`.
        Self::C                  // `Self::C` 是常量值 `9`.
    }
}
<span class="boring">}
</span></code></pre></pre>
<h3><a class="header" href="#super" id="super"><code>super</code></a></h3>
<p><code>super</code> 在路径中被解析为父模块。它只能用于路径的前导段，可以置于 <code>self</code> 路径段之后。</p>
<pre><pre class="playground"><code class="language-rust edition2018">mod a {
    pub fn foo() {}
}
mod b {
    pub fn foo() {
        super::a::foo(); // 调用 a'的 foo 函数
    }
}
<span class="boring">fn main() {}
</span></code></pre></pre>
<p><code>super</code> 可以在第一个 <code>super</code> 或 <code>self</code> 之后重复多次，以引用祖先模块。</p>
<pre><pre class="playground"><code class="language-rust edition2018">mod a {
    fn foo() {}

    mod b {
        mod c {
            fn foo() {
                super::super::foo(); // 调用 a'的 foo 函数
                self::super::super::foo(); // 调用 a'的 foo 函数
            }
        }
    }
}
<span class="boring">fn main() {}
</span></code></pre></pre>
<h3><a class="header" href="#crate" id="crate"><code>crate</code></a></h3>
<p><code>crate</code> 解析相对于当前 crate 的路径。crate 仅能用作路径的首段，不能有前置 <code>::</code>。</p>
<pre><pre class="playground"><code class="language-rust edition2018">fn foo() {}
mod a {
    fn bar() {
        crate::foo();
    }
}
<span class="boring">fn main() {}
</span></code></pre></pre>
<h3><a class="header" href="#crate-1" id="crate-1"><code>$crate</code></a></h3>
<p>$crate 仅用在<a href="macros-by-example.html">宏转码器(macro transcriber)</a>中，且仅能用作路径首段，不能有前置 <code>::</code>。<code>$crate</code> 将被扩展为从定义宏的 crate 的顶层访问该 crate 中的各程序项的路径，而不用去考虑宏调用发生时所在的现场 crate。</p>
<pre><pre class="playground"><code class="language-rust edition2018">pub fn increment(x: u32) -&gt; u32 {
    x + 1
}

#[macro_export]
macro_rules! inc {
    ($x:expr) =&gt; ( $crate::increment($x) )
}
<span class="boring">fn main() { }
</span></code></pre></pre>
<h2><a class="header" href="#canonical-paths" id="canonical-paths">Canonical paths</a></h2>
<h2><a class="header" href="#规范路径" id="规范路径">规范路径</a></h2>
<p>定义在模块或者实现中的程序项都有一个<em>规范路径</em>，该路径对应于其在其 crate 中定义的位置。在该路径之外，所有指向这些程序项的路径都是别名（路径）。规范路径被定义为一个<em>路径前缀</em>后跟一个代表程序项本身的那段路径段。</p>
<p>尽管实现所定义/实现的程序项有规范路径，但<a href="items/implementations.html">实现</a>作为一个整体，自身没有规范路径。<a href="items/use-declarations.html">use声明</a>也没有规范路径。块表达式中定义的程序项也没有规范路径。在没有规范路径的模块中定义的程序项也没有规范路径。在实现中定义的关联项(associated items)如果它指向没有规范路径的程序项——例如，实现类型(implementing type)、被实现的 trait、类型参数或类型参数上的约束——那它也没有规范路径。</p>
<p>模块的路径前缀就是该模块的规范路径。对于裸实现(bare implementations)来说，它里面的程序项的路径前缀是：它当前实现的程序项的规范路径，再用<span class="parenthetical">尖括号（<code>&lt;&gt;</code>）</span>括把此路径括起来。对于 <a href="items/implementations.html#trait-implementations">trait实现</a>来说，它内部的程序项的路径前缀是：<em>当前实现的程序项的规范路径后跟一个 <code>as</code>，再后跟 trait 本身的规范路径，然后整个使用<span class="parenthetical">尖括号（<code>&lt;&gt;</code>）</span>括起来。</em></p>
<p>规范路径只在给定的 crate 中有意义。在 crate 之间没有全局命名空间，所以程序项的规范路径只在其 crate 中可标识。</p>
<pre><pre class="playground"><code class="language-rust edition2018">// 注释解释了程序项的规范路径

mod a { // ::a
    pub struct Struct; // ::a::Struct

    pub trait Trait { // ::a::Trait
        fn f(&amp;self); // ::a::Trait::f
    }

    impl Trait for Struct {
        fn f(&amp;self) {} // &lt;::a::Struct as ::a::Trait&gt;::f
    }

    impl Struct {  // 译者注：这是一个裸实现
        fn g(&amp;self) {} // &lt;::a::Struct&gt;::g
    }
}

mod without { // ::without
    fn canonicals() { // ::without::canonicals
        struct OtherStruct; // None

        trait OtherTrait { // None
            fn g(&amp;self); // None
        }

        impl OtherTrait for OtherStruct {
            fn g(&amp;self) {} // None
        }

        impl OtherTrait for crate::a::Struct {
            fn g(&amp;self) {} // None
        }

        impl crate::a::Trait for OtherStruct {
            fn f(&amp;self) {} // None
        }
    }
}

<span class="boring">fn main() {}
</span></code></pre></pre>
<h1><a class="header" href="#name-resolution" id="name-resolution">Name resolution</a></h1>
<h1><a class="header" href="#名称解析" id="名称解析">名称解析</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/names/name-resolution.md">use-declarations.md</a><br />
commit: eabdf09207bf3563ae96db9d576de0758c413d5d <br />
本章译文最后维护日期：2021-1-24</p>
</blockquote>
<blockquote>
<p><strong>注意</strong>：这是未来本章内容扩展的占位符。</p>
</blockquote>
<h1><a class="header" href="#visibility-and-privacy" id="visibility-and-privacy">Visibility and Privacy</a></h1>
<h1><a class="header" href="#可见性与隐私权" id="可见性与隐私权">可见性与隐私权</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/visibility-and-privacy.md">visibility-and-privacy.md</a><br />
commit: 6ab78176d305f1fe9b5186a940676293c1ad31ef <br />
本章译文最后维护日期：2021-06-19</p>
</blockquote>
<blockquote>
<p><strong><sup>句法<sup></strong><br />
<em>Visibility</em> :<br />
      <code>pub</code><br />
   | <code>pub</code> <code>(</code> <code>crate</code> <code>)</code><br />
   | <code>pub</code> <code>(</code> <code>self</code> <code>)</code><br />
   | <code>pub</code> <code>(</code> <code>super</code> <code>)</code><br />
   | <code>pub</code> <code>(</code> <code>in</code> <a href="paths.html#simple-paths"><em>SimplePath</em></a> <code>)</code></p>
</blockquote>
<p>这两个术语经常互换使用，它们试图表达的是对“这个地方能使用这个程序项吗？”这个问题的回答。</p>
<p>Rust 的名称解析是在命名空间的层级结构的全局层（即最顶层）上运行的。此层级结构中的每个级别都可以看作是某个程序项。这些程序项就是我们前面提到的那些程序项之一（注意这也包括外部crate）。声明或定义一个新模块可以被认为是在定义的位置向此层次结构中插入一个新的（层级）树。</p>
<p>为了控制接口是否可以被跨模块使用，Rust 会检查每个程序项的使用，来看看它是否被允许使用。此处就是生成隐私告警的地方，或者说是提示：“you used a private item of another module and weren't allowed to.”的地方。（译者注：这句提示可以翻译为：您使用了另一个模块的私有程序项，但不允许这样做。）</p>
<p>默认情况下，Rust 中的所有内容都是<em>私有的</em>，但有两个例外：<code>pub</code> trait 中的关联程序项默认为公有的；<code>pub</code> 枚举中的枚举变体也默认为公有的。当一个程序项被声明为 <code>pub</code> 时，它可以被认为是外部世界能以访问的。例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018"><span class="boring">fn main() {}
</span>// 声明一个私有结构体
struct Foo;

// 声明一个带有私有字段的公有结构体
pub struct Bar {
    field: i32,
}

// 声明一个带有两个公有变体的公有枚举
pub enum State {
    PubliclyAccessibleState,
    PubliclyAccessibleState2,
}
</code></pre></pre>
<p>依据程序项是公有的还是私有的，Rust 分两种情况来访问数据：</p>
<ol>
<li>
<p>如果某个程序项是公有的，那么如果可以从外部的某一模块 <code>m</code> 访问到该程序项的所有祖先模块，则一定可以从这个模块 <code>m</code> 中访问到该程序项。甚至还可以通过重导出来命名该程序项。具体见后文。</p>
</li>
<li>
<p>如果某个程序项是私有的，则当前模块及当前模块的后代模块都可以访问它。</p>
</li>
</ol>
<p>这两种情况在创建能对外暴露公共API 同时又隐藏内部实现细节的模块层次结构时非常好用。为了帮助理解，以下是一些常见案例和它们需要做的事情：</p>
<ul>
<li>
<p>库开发人员需要将一些功能暴露给链接了其库的 crate。作为第一种情况的结果，这意味着任何那些在外部可用的程序项自身以及其路径层级结构中的每一层都必须是公有的(<code>pub</code>)的。并且此层级链中的任何私有程序项都不允许被外部访问。</p>
</li>
<li>
<p>crate 需要一个全局可用的“辅助模块(helper module)”，但又不想将辅助模块公开为公共API。为了实现这一点，可以在整个 crate 的根模块（路径层级结构中的最顶层）下建一个私有模块，该模块在内部是“公共API”。因为整个 crate 都是根模块的后代，所以整个本地 crate 里都可以通过第二种情况访问这个私有模块。</p>
</li>
<li>
<p>在为模块编写单元测试时，通常的习惯做法是给要测试的模块加一个命名为 <code>mod test</code> 的直接子模块。这个模块可以通过第二种情况访问父模块的任何程序项，这意味着内部实现细节也可以从这个子模块里进行无缝地测试。</p>
</li>
</ul>
<p>在第二种情况下，我们提到了当前模块及其后代“可以访问”私有项，但是访问一个程序项的确切含义取决于该项是什么。例如，访问一个模块意味着要查看它的内部（以导入更多的程序项）；访问一个函数意味着它被调用了。此外，路径表达式和导入语句也被视为访问一个程序项，但只有当访问目标位于当前可见的作用域内时，它们才算是有效的数据访问。</p>
<p>下面是一段示例程序，它例证了上述三种情况：</p>
<pre><pre class="playground"><code class="language-rust edition2018">// 这个模块是私有的，这意味着没有外部crate 可以访问这个模块。
// 但是，由于它在当前 crate 的根模块下，
// 因此当前 crate 中的任何模块都可以访问该模块中任何公有可见性程序项。
mod crate_helper_module {

    // 这个函数可以被当前 crate 中的任何东西使用
    pub fn crate_helper() {}

    // 此函数*不能*被用于 crate 中的任何其他模块中。它在 `crate_helper_module` 之外不可见，
    // 因此只有当前模块及其后代可以访问它。
    fn implementation_detail() {}
}

// 此函数“对根模块是公有”的，这意味着它可被链接了此crate 的其他crate 使用。
pub fn public_api() {}

// 与 'public_api' 类似，此模块是公有的，因此其他的crate 是能够看到此模块内部的。
pub mod submodule {
    use crate::crate_helper_module;

    pub fn my_method() {
        // 本地crate 中的任何程序项都可以通过上述两个规则的组合来调用辅助模块里的公共接口。
        crate_helper_module::crate_helper();
    }

    // 此函数对任何不是 `submodule` 的后代的模块都是隐藏的
    fn my_implementation() {}

    #[cfg(test)]
    mod test {

        #[test]
        fn test_my_implementation() {
            // 因为此模块是 `submodule` 的后代，因此允许它访问 `submodule` 内部的私有项，而不会侵犯隐私权。
            super::my_implementation();
        }
    }
}

<span class="boring">fn main() {}
</span></code></pre></pre>
<p>对于一个 Rust 程序要通过隐私检查，所有的路径都必须满足上述两个访问规则。这里说的路径包括所有的 use语句、表达式、类型等。</p>
<h2><a class="header" href="#pubin-path-pubcrate-pubsuper-and-pubself" id="pubin-path-pubcrate-pubsuper-and-pubself"><code>pub(in path)</code>, <code>pub(crate)</code>, <code>pub(super)</code>, and <code>pub(self)</code></a></h2>
<p>除了公有和私有之外，Rust 还允许用户（用关键字 <code>pub</code> ）声明仅在给定作用域内可见的程序项。声明形式的限制规则如下：</p>
<ul>
<li><code>pub(in path)</code> 使一个程序项在提供的 <code>path</code> 中可见。<code>path</code> 必须是声明其可见性的程序项的祖先模块。</li>
<li><code>pub(crate)</code> 使一个程序项在当前 crate 中可见。</li>
<li><code>pub(super)</code> 使一个程序项对父模块可见。这相当于 <code>pub(in super)</code>。</li>
<li><code>pub(self)</code> 使一个程序项对当前模块可见。这相当于 <code>pub(in self)</code> 或者根本不使用 <code>pub</code>。</li>
</ul>
<blockquote>
<p><strong>版本差异</strong>: 从 2018版开始，<code>pub(in path)</code> 的路径必须以 <code>crate</code>、<code>self</code>或<code>super</code>开头。2015版还可以使用以 <code>::</code> 开头的路径，或以根模块下的模块名的开头的路径。</p>
</blockquote>
<p>这里是一些示例：</p>
<pre><pre class="playground"><code class="language-rust edition2015">pub mod outer_mod {
    pub mod inner_mod {
        // 此函数在 `outer_mod` 内部可见
        pub(in crate::outer_mod) fn outer_mod_visible_fn() {}
        // 同上，但这只能在2015版中有效
        pub(in outer_mod) fn outer_mod_visible_fn_2015() {}

        // 此函数对整个 crate 都可见
        pub(crate) fn crate_visible_fn() {}

        // 此函数在 `outer_mod` 下可见
        pub(super) fn super_mod_visible_fn() {
            // 此函数之所以可用，是因为我们在同一个模块下
            inner_mod_visible_fn();
        }

        // 这个函数只在 `inner_mod` 中可见，这与它保持私有的效果是一样的。
        pub(self) fn inner_mod_visible_fn() {}
    }
    pub fn foo() {
        inner_mod::outer_mod_visible_fn();
        inner_mod::crate_visible_fn();
        inner_mod::super_mod_visible_fn();

        // 此函数不再可见，因为我们在  `inner_mod` 之外
        // 错误! `inner_mod_visible_fn` 是私有的
        //inner_mod::inner_mod_visible_fn();
    }
}

fn bar() {
    // 此函数仍可见，因为我们在同一个 crate 里
    outer_mod::inner_mod::crate_visible_fn();

    // 此函数不再可见，因为我们在`outer_mod`之外
    // 错误! `super_mod_visible_fn` 是私有的
    //outer_mod::inner_mod::super_mod_visible_fn();

    // 此函数不再可见，因为我们在`outer_mod`之外
    // 错误! `outer_mod_visible_fn` 是私有的
    //outer_mod::inner_mod::outer_mod_visible_fn();

    outer_mod::foo();
}

fn main() { bar() }
</code></pre></pre>
<blockquote>
<p><strong>注意:</strong> 此句法仅对程序项的可见性添加了另一个限制。它不能保证该程序项在指定作用域的所有部分都可见。要访问一个程序项，当前作用域内它的所有父项还是必须仍然可见。</p>
</blockquote>
<h2><a class="header" href="#re-exporting-and-visibility" id="re-exporting-and-visibility">Re-exporting and Visibility</a></h2>
<h2><a class="header" href="#重导出和可见性" id="重导出和可见性">重导出和可见性</a></h2>
<p>Rust 允许使用指令 <code>pub use</code> 公开重导出程序项。因为这是一个公有指令，所以允许通过上面的规则验证后在当前模块中使用该程序项。重导出本质上允许使用公有方式访问重导出的程序项的内部。例如，下面程序是有效的：</p>
<pre><pre class="playground"><code class="language-rust edition2018">pub use self::implementation::api;

mod implementation {
    pub mod api {
        pub fn f() {}
    }
}

<span class="boring">fn main() {}
</span></code></pre></pre>
<p>这意味着任何外部 crate，只要引用 <code>implementation::api::f</code> 都将收到违反隐私的错误报告，而使用路径 <code>api::f</code> 则被允许。</p>
<p>当重导出私有程序项时，可以认为它允许通过重导出短路了“隐私链(privacy chain)”，而不是像通常那样通过命名空间层次结构来传递“隐私链”。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#memory-model" id="memory-model">Memory model</a></h1>
<h1><a class="header" href="#内存模型" id="内存模型">内存模型</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/memory-model.md">memory-model.md</a><br />
commit: 2d3085f1bab9d751e8a9b92c3b27c049ad23fdd7 <br />
本章译文最后维护日期：2020-11-2</p>
</blockquote>
<p>Rust 还没有明确的内存模型。许多学者和行业专业人士正在研究各种提案，但就目前而言，这在该语言中仍是一个未明确定义的地方。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#memory-allocation-and-lifetime" id="memory-allocation-and-lifetime">Memory allocation and lifetime</a></h1>
<h1><a class="header" href="#内存分配和生存期" id="内存分配和生存期">内存分配和生存期</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/memory-allocation-and-lifetime.md">memory-allocation-and-lifetime.md</a><br />
commit: af1cf6d3ca3b7a8c434c142148742aa912e37c34 <br />
本章译文最后维护日期：2020-11-16</p>
</blockquote>
<p>程序的<em>程序项</em>是那些函数、模块和类型，它们的值在编译时被计算出来，并且唯一地存储在 Rust 进程的内存映像中。程序项既不是动态分配的，也不是动态释放的。</p>
<p><em>堆</em>是描述 box类型（译者注：box是一种堆分配形式，该堆分配返回一个指向该堆分配的内存地址的指针，后文称这个指针为 box指针或 box引用）的通用术语。堆分配的生存期取决于指向它的 box指针的生存期。由于 box指针本身可能被传入或传出栈帧，或者存储在堆中，因此堆分配可能比初始分配它们的栈帧存活的时间长。在堆分配的整个生存期内，该堆分配被保证驻留在堆中的单一位置 — 它永远不会因移动 box指针而重新分配内存地址。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#variables" id="variables">Variables</a></h1>
<h1><a class="header" href="#变量" id="变量">变量</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/variables.md">variables.md</a><br />
commit: 79fcc6e4453919977b8b3bdf5aee71146c89217d <br />
本章译文最后维护日期：2020-11-16</p>
</blockquote>
<p><em>变量</em>是栈帧里的一个组件，可以是具名函数参数、匿名的<a href="expressions.html#temporaries">临时变量</a>或具名局部变量。</p>
<p><em>局部变量</em>（或*本地栈(stack-local)*分配）直接持有一个值，该值在栈内存中分配。该值是栈帧的一部分。</p>
<p>局部变量是不可变的，除非特别声明。例如：<code>let mut x = ...</code>。</p>
<p>函数参数是不可变的，除非用 <code>mut</code> 声明。关键字 <code>mut</code> 只应用于紧跟着它的那个参数。例如：<code>|mut x, y|</code> 和 <code>fn f(mut x: Box&lt;i32&gt;, y: Box&lt;i32&gt;)</code> 声明了一个可变变量 <code>x</code> 和一个不可变变量 <code>y</code>。</p>
<p>分配时不会初始化局部变量。此处一反常态的是在帧建立时，以未初始化状态分配整个帧值的局部变量。函数中的后续语句可以初始化局部变量，也可以不初始化局部变量。局部变量只有在通过所有可到达的控制流路径初始化后才能使用</p>
<p>在下面示例中，<code>init_after_if</code> 是在 <a href="expressions/if-expr.html#if-expressions"><code>if</code>表达式</a>执行后被初始化的，而 <code>uninit_after_if</code> 不是，因为它没有在 <code>else</code> 分支里被初始化。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span><span class="boring">fn random_bool() -&gt; bool { true }
</span>fn initialization_example() {
    let init_after_if: ();
    let uninit_after_if: ();

    if random_bool() {
        init_after_if = ();
        uninit_after_if = ();
    } else {
        init_after_if = ();
    }

    init_after_if; // ok
    // uninit_after_if; // 错误：使用可能未初始化的 `uninit_after_if`
}
<span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#linkage" id="linkage">Linkage</a></h1>
<h1><a class="header" href="#链接" id="链接">链接</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/linkage.md">linkage.md</a><br />
commit: 1426474192ecc9c13165c1d4772b26e8445f5734<br />
本章译文最后维护日期：2021-4-23</p>
</blockquote>
<blockquote>
<p>注意：本节更多的是从编译器的角度来描述的，而不是语言。</p>
</blockquote>
<p>Rust 编译器支持多种将 crate 链接起来使用的方法，这些链接方法可以是静态的，也可以是动态的。本节将聚焦探索这些链接方法，关于本地库的更多信息请参阅 <a href="https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code">The Book 中的 FFI 相关章节</a>。</p>
<p>在一个编译会话中，编译器可以通过使用命令行参数或内部 <code>crate_type</code>属性来生成多个构件(artifacts)。如果指定了一个或多个命令行参数，则将忽略（源码内部指定的）所有 <code>crate_type</code>属性，以便只构建由命令行指定的构件。</p>
<ul>
<li>
<p><code>--crate-type=bin</code> 或 <code>#[crate_type = &quot;bin&quot;]</code> - 将生成一个可执行文件。这就要求在 crate 中有一个 <code>main</code>函数，它将在程序开始执行时运行。这将链接所有 Rust 和本地依赖，生成一个单独的可分发的二进制文件。此类型为默认的 crate 类型。</p>
</li>
<li>
<p><code>--crate-type=lib</code> 或 <code>#[crate_type = &quot;lib&quot;]</code> - 将生成一个 Rust库(library)。但最终会确切输出/生成什么类型的库在未生成之前还不好清晰确定，因为库有多种表现形式。使用 <code>lib</code> 这个通用选项的目的是生成“编译器推荐”的类型的库。像种指定输出库类型的选项在 rustc 里始终可用，但是每次实际输出的库的类型可能会随着实际情况的不同而不同。其它的输出（库的）类型选项都指定了不同风格的库类型，而 <code>lib</code> 可以看作是那些类型中的某个类型的别名（具体实际的输出的类型是编译器决定的）。</p>
</li>
<li>
<p><code>--crate-type=dylib</code> 或 <code>#[crate_type = &quot;dylib&quot;]</code> - 将生成一个动态 Rust库。这与 <code>lib</code> 选项的输出类型不同，因为这个选项会强制生成动态库。生成的动态库可以用作其他库和/或可执行文件的依赖。这种输出类型将创建依赖于具体平台的库（Linux 上为 <code>*.so</code>，macOS 上为 <code>*.dylib</code>、Windows 上为 <code>*.dll</code>）。</p>
</li>
<li>
<p><code>--crate-type=staticlib</code> 或 <code>#[crate_type = &quot;staticlib&quot;]</code> - 将生成一个静态系统库。这个选项与其他选项的库输出的不同之处在于——当前编译器永远不会尝试去链接此 <code>staticlib</code> 输出<sup class="footnote-reference"><a href="#译注1">1</a></sup>。此选项的目的是创建一个包含所有本地 crate 的代码以及所有上游依赖的静态库。此输出类型将在 Linux、macOS 和 Windows(MinGW) 平台上创建 <code>*.a</code> 归档文件(archive)，或者在 Windows(MSVC) 平台上创建 <code>*.lib</code> 库文件。在这些情况下，例如将 Rust代码链接到现有的非 Rust应用程序中，推荐使用这种类型，因为它不会动态依赖于其他 Rust 代码。</p>
</li>
<li>
<p><code>--crate-type=cdylib</code> 或 <code>#[crate_type = &quot;cdylib&quot;]</code> - 将生成一个动态系统库。如果编译输出的动态库要被另一种语言加载使用，请使用这种编译选项。这种选项的输出将在 Linux 上创建 <code>*.so</code> 文件，在 macOS 上创建 <code>*.dylib</code> 文件，在 Windows 上创建 <code>*.dll</code> 文件。</p>
</li>
<li>
<p><code>--crate-type=rlib</code> 或 <code>#[crate_type = &quot;rlib&quot;]</code> - 将生成一个“Rust库”。它被用作一个中间构件，可以被认为是一个“静态 Rust库”。与 <code>staticlib</code> 类型的库文件不同，这些 <code>rlib</code> 类型的库文件以后会作为其他 Rust代码文件的上游依赖，未来对那些 Rust代码文件进行编译时，那时的编译器会链并解释此 <code>rlib</code>文件。这本质上意味着（那时的） <code>rustc</code> 将在（此） <code>rlib</code> 文件中查找元数据(metadata)，就像在动态库中查找元数据一样。跟 <code>staticlib</code> 输出类型类似，这种类型的输出常配合用于生成静态链接的可执行文件(statically linked executable)。</p>
</li>
<li>
<p><code>--crate-type=proc-macro</code> 或 <code>#[crate_type = &quot;proc-macro&quot;]</code> - 生成的输出类型没有被指定，但是如果通过 <code>-L</code> 提供了路径参数，编译器将把输出构件识别为宏，输出的宏可以被其他 Rust 程序加载使用。使用此 crate 类型编译的 crate 只能导出<a href="procedural-macros.html">过程宏</a>。编译器将自动设置 <code>proc_macro</code><a href="conditional-compilation.html">属性配置选项</a>。编译 crate 的目标平台(target)总是和当前编译器所在平台一致。例如，如果在 <code>x86_64</code> CPU 的 Linux 平台上执行编译，那么目标将是 <code>x86_64-unknown-linux-gnu</code>，即使该 crate 是另一个不同编译目标的 crate 的依赖。</p>
</li>
</ul>
<p>请注意，这些选项是可堆叠使用的，如果同时使用了多个选项，那么编译器将一次生成所有这些选项关联的的输出类型，而不必反复多次编译。但是，命令行和内部 <code>crate_type</code> 属性配置不能同时起效。如果只使用了不带属性值的 <code>crate_type</code> 属性配置，则将生成所有类型的输出，但如果同时指定了一个或多个 <code>--crate-type</code> 命令行参数，则只生成这些指定的输出。</p>
<p>对于所有这些不同类型的输出，如果 crate A 依赖于 crate B，那么整个系统中很可能有多种不同形式的 B，但是，编译器只会查找 <code>rlib</code> 类型的和动态库类型的。有了依赖库的这两个选项，编译器在某些时候还是必须在这两种类型之间做出选择。考虑到这一点，编译器在决定使用哪种依赖关系类型时将遵循以下规则：</p>
<ol>
<li>
<p>如果当前生成静态库，则需要所有上游依赖都以 <code>rlib</code> 类型可用。这个需求源于不能将动态库转换为静态类型的原因。</p>
<p>注意，不可能将本地动态依赖链接到静态库，在这种情况下，将打印有关所有未链接的本地动态依赖的警告。</p>
</li>
<li>
<p>如果当前生成 <code>rlib</code> 文件，则对上游依赖的可用类型没有任何限制，仅需要求所有这些文件都可以从其中读出元数据。</p>
<p>原因是 <code>rlib</code> 文件不包含它们的任何上游依赖。但如果所有的 <code>rlib</code> 文件都包含一份 <code>libstd.rlib</code> 的副本，那编译效率和执行效率将大幅降低。</p>
</li>
<li>
<p>如果当前生成可执行文件，并且没有指定 <code>-C prefer-dynamic</code> 参数，则首先尝试以 <code>rlib</code> 类型查找依赖。如果某些依赖在 rlib 类型文件中不可用，则尝试动态链接（见下文）。</p>
</li>
<li>
<p>如果当前生成动态链接的动态库或可执行文件，则编译器将尝试协调从 rlib 或 dylib 类型的文件里获取可用依赖关系，以创建最终产品。</p>
<p>编译器的主要目标是确保任何一个库不会在任何构件中出现多次。例如，如果动态库 B 和 C 都静态地去链接了库 A，那么当前 crate 就不能同时链接到 B 和 C，因为 A 有两个副本。编译器允许混合使用 rlib 和 dylib 类型，但这一限制必须被满足。</p>
<p>编译器目前没有实现任何方法来提示库应该链接到哪种类型的库。当选择动态链接时，编译器将尝试最大化动态依赖，同时仍然允许通过 rlib 类型链接某些依赖。</p>
<p>对于大多数情况，如果所有的可用库都是 dylib 类型的动态库，则推荐选择动态链接。对于其他情况，如果编译器无法确定一个库到底应该去链接它的哪种类型的版本，则会发布警告。</p>
</li>
</ol>
<p>通常，<code>--crate-type=bin</code> 或 <code>--crate-type=lib</code> 应该足以满足所有的编译需求，只有在需要对 crate 的输出类型进行更细粒度的控制时，才需要使用其他选项。</p>
<h2><a class="header" href="#static-and-dynamic-c-runtimes" id="static-and-dynamic-c-runtimes">Static and dynamic C runtimes</a></h2>
<h2><a class="header" href="#静态c运行时和动态c运行时" id="静态c运行时和动态c运行时">静态C运行时和动态C运行时</a></h2>
<p>一般来说，标准库会同时尽力支持编译目标的静态链接型C运行时和动态链接型C运行时。例如，目标 <code>x86_64-pc-windows-msvc</code> 和 <code>x86_64-unknown-linux-musl</code> 通常都带有C运行时，用户可以按自己的偏好去选择静态链接或动态链接到此运行时。编译器中所有的编译目标都有一个链接到 C运行时的默认模式。默认情况下，常见的编译目标都默认是选择动态链接的，但也存在默认情况下是静态链接的情况，例如：</p>
<ul>
<li><code>arm-unknown-linux-musleabi</code></li>
<li><code>arm-unknown-linux-musleabihf</code></li>
<li><code>armv7-unknown-linux-musleabihf</code></li>
<li><code>i686-unknown-linux-musl</code></li>
<li><code>x86_64-unknown-linux-musl</code></li>
</ul>
<p>C运行时的链接类型被配置为通过 <code>crt-static</code> 目标特性值来开启。这些目标特性通常是从命令行通过命令行参数传递给编译器来设置的。例如，要启用静态运行时，应该执行：</p>
<pre><code class="language-sh">rustc -C target-feature=+crt-static foo.rs
</code></pre>
<p>如果想动态链接到C运行时，应该执行：</p>
<pre><code class="language-sh">rustc -C target-feature=-crt-static foo.rs
</code></pre>
<p>不支持在到 C运行时的链接类型之间切换的编译目标将忽略这个标志。建议检查生成的二进制文件，以确保在编译成功之后，如预期的那样链接了 C运行时。</p>
<p>crate 本身也可以检测如何链接 C运行时。例如，MSVC平台上的代码需要根据链接运行时的方式进行差异性的编译（例如选择使用 <code>/MT</code> 或 <code>/MD</code>）。目前可通过 <a href="conditional-compilation.html#target_feature"><code>cfg</code>属性的 <code>target_feature</code>选项</a>导出检测结果：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[cfg(target_feature = &quot;crt-static&quot;)]
fn foo() {
    println!(&quot;C运行时应该被静态链接&quot;);
}

#[cfg(not(target_feature = &quot;crt-static&quot;))]
fn foo() {
    println!(&quot;C运行时应该被动态链接&quot;);
}
<span class="boring">}
</span></code></pre></pre>
<p>还请注意，Cargo构建脚本可以通过<a href="https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts">环境变量</a>来检测此特性。在构建脚本中，您可以通过如下代码检测链接类型：</p>
<pre><pre class="playground"><code class="language-rust edition2018">use std::env;

fn main() {
    let linkage = env::var(&quot;CARGO_CFG_TARGET_FEATURE&quot;).unwrap_or(String::new());

    if linkage.contains(&quot;crt-static&quot;) {
        println!(&quot;C运行时应该被静态链接&quot;);
    } else {
        println!(&quot;C运行时应该被动态链接&quot;);
    }
}
</code></pre></pre>
<p>要在本地使用此特性，通常需要使用 <code>RUSTFLAGS</code> 环境变量通过 Cargo 来为编译器指定参数。例如，要在 MSVC 平台上编译静态链接的二进制文件，需要执行：</p>
<pre><code class="language-sh">RUSTFLAGS='-C target-feature=+crt-static' cargo build --target x86_64-pc-windows-msvc
</code></pre>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>译者理解此编译选项是将本地 Rust crate 和其上游依赖资源编译输出成一个库，供其他应用程序使用的。所以对当前编译而言，不能依赖还不存在的资源；又因为其他 Rust crate 的编译无法将静态库作为编译时依赖的上游资源，所以编译其他 Rust crate 的编译器也不会来链接此 <code>staticlib</code> 输出。</p>
</div>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#unsafety" id="unsafety">Unsafety</a></h1>
<h1><a class="header" href="#非安全性" id="非安全性">非安全性</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/unsafety.md">unsafety.md</a><br />
commit:  b0e0ad6490d6517c19546b1023948986578fc378 <br />
本章译文最后维护日期：2020-11-2</p>
</blockquote>
<p>非安全操作(Unsafe operations)是那些可能潜在地违反 Rust 静态语义里的和内存安全保障相关的操作。</p>
<p>以下语言级别的特性不能在 Rust 的安全(safe)子集中使用:</p>
<ul>
<li>读取或写入<a href="items/static-items.html#mutable-statics">可变</a>静态变量；读取或写入或<a href="items/external-blocks.html">外部</a>静态变量。</li>
<li>访问[联合体(<code>union</code>)]的字段，注意不是给它的字段赋值。</li>
<li>调用一个非安全(unsafe)函数（包括外部函数和和内部函数(intrinsic)）。</li>
<li>实现<a href="items/traits.html#unsafe-traits">非安全(unsafe) trait</a>.</li>
</ul>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#unsafe-functions" id="unsafe-functions">Unsafe functions</a></h1>
<h1><a class="header" href="#非安全函数" id="非安全函数">非安全函数</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/unsafe-functions.md">unsafe-functions.md</a><br />
commit:  4a2bdf896cd2df370a91d14cb8ba04e326cd21db <br />
本章译文最后维护日期：2020-11-16</p>
</blockquote>
<p>非安全函数是指在任何可能的上下文和/或任何可能的输入中可能出现不安全情况的函数。这样的函数必须以关键字 <code>unsafe</code> 前缀修饰，并且只能在非安全(<code>unsafe</code>)块或其他非安全(<code>unsafe</code>)函数中调用此类函数。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#unsafe-blocks-1" id="unsafe-blocks-1">Unsafe blocks</a></h1>
<h1><a class="header" href="#非安全块" id="非安全块">非安全块</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/unsafe-blocks.md">unsafe-blocks.md</a><br />
commit:  4a2bdf896cd2df370a91d14cb8ba04e326cd21db <br />
本章译文最后维护日期：2020-11-16</p>
</blockquote>
<p>一个代码块可以以关键字 <code>unsafe</code> 作为前缀，以允许在安全(safe)函数中调用非安全(<code>unsafe</code>)函数或对裸指针做解引用操作。</p>
<p>当程序员确信某些潜在的非安全操作实际上是安全的，他们可以将这段代码（作为一个整体）封装进一个非安全(<code>unsafe</code>)块中。编译器将认为在当前的上下文中使用这样的代码是安全的。</p>
<p>非安全块用于封装外部库、直接操作硬件或实现语言中没有直接提供的特性。例如，Rust 提供了实现内存安全并发所需的语言特性，但是线程和消息传递的实现（没在语言中实现，而）是在标准库中实现的。</p>
<p>Rust 的类型系统是动态安全条款(dynamic safety requirements)的保守近似值，因此在某些情况下使用安全代码会带来性能损失。例如，双向链表不是树型结构，那在安全代码中，只能妥协使用引用计数指针表示。通过使用非安全(<code>unsafe</code>)块，可以将反向链接表示为原始指针，这样只用一层 box封装就能实现了。</p>
<!-- 2020-11-12-->
<!-- checked -->
<h2><a class="header" href="#behavior-considered-undefined" id="behavior-considered-undefined">Behavior considered undefined</a></h2>
<h2><a class="header" href="#未定义的行为" id="未定义的行为">未定义的行为</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/behavior-considered-undefined.md">behavior-considered-undefined.md</a><br />
commit: 5524a17a22c94ad21ab28d545c316909ebda0e31 <br />
本章译文最后维护日期：2021-4-11</p>
</blockquote>
<p>如果 Rust 代码出现了下面列表中的任何行为，则此代码被认为不正确。这包括非安全(<code>unsafe</code>)块和非安全函数里的代码。非安全只意味着避免出现未定义行为(undefined behavior)的责任在程序员；它没有改变任何关于 Rust 程序必须确保不能写出导致未定义行为的代码的事实。</p>
<p>在编写非安全代码时，确保任何与非安全代码交互的安全代码不会触发下述未定义行为是程序员的责任。对于任何使用非安全代码的安全客户端(safe client)，如果当前条件满足了此非安全代码对于安全条件的要求，那此此非安全代码对于此安全客户端就是<em>健壮的(sound)</em>；如果非安全(<code>unsafe</code>)代码可以被安全代码滥用以致出现未定义行为，那么此非安全(<code>unsafe</code>)代码对这些安全代码来说就是<em>不健壮的(unsound)</em>。</p>
<div class="warning">
<p><em><strong>警告：</strong></em> 下面的列表并非详尽无遗地罗列了 Rust 中的未定义行为。而且对于在非安全代码中什么是明确不允许的，目前 Rust 还没有正式的语义模型，因此将来可能会有更多的行为被认为是不安全的。下面的列表仅仅是我们当前确定知晓的未定义行为。在编写非安全代码之前，请阅读 <a href="https://doc.rust-lang.org/nomicon/index.html">Rustonomicon</a>。</p>
</div>
<ul>
<li>数据竞争。</li>
<li>在<a href="behavior-considered-undefined.html#dangling-pointers">悬垂</a>或未对齐的裸指针上执行<a href="expressions/operator-expr.html#the-dereference-operator">解引用操作</a> (<code>*expr</code>)，甚至<a href="expressions.html#place-expressions-and-value-expressions">位置表达式</a>(e.g. <code>addr_of!(&amp;*expr)</code>)上也不安全。</li>
<li>破坏<a href="http://llvm.org/docs/LangRef.html#pointer-aliasing-rules">指针别名规则</a>。<code>&amp;mut T</code> 和 <code>&amp;T</code> 遵循 LLVM 的作用域<a href="http://llvm.org/docs/LangRef.html#noalias">无别名(noalias)</a>模型(scoped noalias model)，除非 <code>&amp;T</code> 内部包含 <a href="https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html"><code>UnsafeCell&lt;U&gt;</code></a> 类型。</li>
<li>修改不可变的数据。<a href="items/constant-items.html">常量(<code>const</code>)</a>项内的所有数据都是不可变的。此外，所有通过共享引用接触到的数据或不可变绑定所拥有的数据都是不可变的，除非该数据包含在 <a href="https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html"><code>UnsafeCell&lt;U&gt;</code></a> 中。</li>
<li>通过编译器内部函数(compiler intrinsics)调用未定义行为。<sup class="footnote-reference"><a href="#译注1">1</a></sup></li>
<li>执行基于当前平台不支持的平台特性编译的代码（参见 <a href="attributes/codegen.html#the-target_feature-attribute"><code>target_feature</code></a>）。</li>
<li>用错误的 ABI约定来调用函数，或使用错误的 ABI展开约定来从某函数里发起展开(unwinding)。</li>
<li>产生非法值(invalid value)，即使在私有字段和本地变量中也是如此。“产生”值发生在这些时候：把值赋给位置表达式、从位置表达式里读取值、传递值给函数/基本运算(primitive operation)或从函数/基本运算中返回值。
以下值非法值（相对于它们各自的类型来说）：
<ul>
<li>
<p>布尔型<a href="types/boolean.html"><code>bool</code></a>中除 <code>false</code> (<code>0</code>) 或 <code>true</code> (<code>1</code>) 之外的值。</p>
</li>
<li>
<p>不包括在该枚举(<code>enum</code>)类型定义中的判别值。</p>
</li>
<li>
<p>指向为空(null)的函数指针(<code>fn</code> pointer)。</p>
</li>
<li>
<p>代理码点(Surrogate)或码点大于 <code>char::MAX</code> 的字符(<code>char</code>)值。</p>
</li>
<li>
<p><code>!</code>类型的值（任何此类型的值都是非法的）。</p>
</li>
<li>
<p>从<a href="http://llvm.org/docs/LangRef.html#undefined-values">未初始化的内存</a>中，或从字符串切片(<code>str</code>)的未初始化部分获取的整数（i*/u*）、浮点值（f*）或裸指针。</p>
</li>
<li>
<p>引用或 <code>Box&lt;T&gt;</code> （代表的指针）指向了<a href="behavior-considered-undefined.html#dangling-pointers">悬垂(dangling)</a>、未对齐或指向非法值。</p>
</li>
<li>
<p>宽(wide)引用、<code>Box&lt;T&gt;</code> 或原始指针中带有非法元数据(metadata)：</p>
<ul>
<li>如果 trait对象(<code>dyn Trait</code>)的元数据不是指向 <code>Trait</code> 的虚函数表(vtable)（该虚函数表与该指针或引用所指向的实际动态 trait 相匹配）的指针，则 <code>dyn Trait</code> 元数据非法。</li>
<li>如果切片的长度不是有效的 <code>usize</code>，则该切片的元数据是非法的（也就是说，不能从它未初始化的内存中读取它）。</li>
</ul>
</li>
<li>
<p>带有非法值的自定义类型的值非法。在标准库中，这条促成了 <a href="https://doc.rust-lang.org/core/ptr/struct.NonNull.html"><code>NonNull&lt;T&gt;</code></a> 和 <a href="https://doc.rust-lang.org/core/num/index.html"><code>NonZero*</code></a> 的出现。</p>
<blockquote>
<p><strong>注意</strong>：<code>rustc</code> 是使用还未稳定下来的属性 <code>rustc_layout_scalar_valid_range_*</code> 来验证这条规则的。</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<p><strong>注意：</strong> 未初始化的内存对于任何具有有限有效值集的类型来说也隐式非法。也就是说，允许读取未初始化内存的情况只发生在联合体(<code>union</code>)内部和“对齐填充区(padding)”里（类型的字段/元素之间的间隙）。</p>
<blockquote>
<p><strong>注意</strong>：未定义行为影响整个程序。例如，在 C 中调用一个 C函数已经出现了未定义行为，这意味着包含此调用的整个程序都包含了未定义行为。如果 Rust 再通过 FFI 来调用这段 C程序/代码，那这段 Rust 代码也包含了未定义行为。反之亦然。因此 Rust 中的未定义行为会对任何其他通过 FFI 过来调用的代码造成不利影响。</p>
</blockquote>
<h3><a class="header" href="#dangling-pointers" id="dangling-pointers">Dangling pointers</a></h3>
<h3><a class="header" href="#悬垂指针" id="悬垂指针">悬垂指针</a></h3>
<p>如果引用/指针为空或者它指向的所有字节不是同一次分配(allocation)的一部分（因此，它们都必须是<em>某次</em>分配的一部分），那么它就是“悬垂”的。它指向的字节跨度(span)由指针本身和指针所指对象的类型的尺寸决定（此尺寸可使用 <code>size_of_val</code> 检测）。因此，如果这个字节跨度为空，则此时“悬垂”与“非空(non-null)”相同。请注意，切片和字符串指向它们的整个区间(range)，因此切片的长度元数据永远不要太大这点很重要。因此切片和字符串的分配不能大于  <code>isize::MAX</code> 个字节。</p>
<div class="footnote-definition" id="译注1"><sup class="footnote-definition-label">1</sup>
<p>因为编译器内部函数(compiler intrinsics)很多都是和平台相关的，移植性差。</p>
</div>
<h2><a class="header" href="#behavior-not-considered-unsafe" id="behavior-not-considered-unsafe">Behavior not considered <code>unsafe</code></a></h2>
<h2><a class="header" href="#不被认为是非安全的行为" id="不被认为是非安全的行为">不被认为是非安全的行为</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/behavior-not-considered-unsafe.md">behavior-not-considered-unsafe.md</a><br />
commit: a7473287cc6e2fb972165dc5a7ffd26dad1fc907 <br />
本章译文最后维护日期：2021-1-16</p>
</blockquote>
<p>虽然程序员可能（应该）发现下列行为是不良的、意外的或错误的，但 Rust 编译器并不认为这些行为是<em>非安全的(unsafe)</em>。</p>
<h5><a class="header" href="#死锁deadlocks" id="死锁deadlocks">死锁(Deadlocks)</a></h5>
<h5><a class="header" href="#内存和其他资源的泄漏leaks-of-memory-and-other-resources" id="内存和其他资源的泄漏leaks-of-memory-and-other-resources">内存和其他资源的泄漏(Leaks of memory and other resources)</a></h5>
<h5><a class="header" href="#退出而不调用析构函数exiting-without-calling-destructors" id="退出而不调用析构函数exiting-without-calling-destructors">退出而不调用析构函数(Exiting without calling destructors)</a></h5>
<h5><a class="header" href="#通过指针泄漏暴露随机基地址exposing-randomized-base-addresses-through-pointer-leaks" id="通过指针泄漏暴露随机基地址exposing-randomized-base-addresses-through-pointer-leaks">通过指针泄漏暴露随机基地址(Exposing randomized base addresses through pointer leaks)</a></h5>
<h5><a class="header" href="#整数溢出integer-overflow" id="整数溢出integer-overflow">整数溢出(Integer overflow)</a></h5>
<p>如果程序包含算术溢出(arithmetic overflow)，则说明程序员犯了错误。在下面的讨论中，我们将区分算术溢出和包装算法(wrapping arithmetic)。前者是错误的，而后者是有意为之的。</p>
<p>当程序员启用了 <code>debug_assert!</code> 断言（例如，通过启用非优化的构建方式），相应的实现就必须插进来以便在溢出时触发 <code>panic</code>。而其他类型的构建形式有可能也在溢出时触发 <code>panics</code>，也有可能仅仅隐式包装一下溢出值，对溢出过程做静音处理。也就是说具体怎么对待溢出由插进来的编译实现决定。</p>
<p>在隐式包装溢出的情况下，（编译器实现的包装算法）实现必须通过使用二进制补码溢出(two's complement overflow)约定来提供定义良好的（即使仍然被认为是错误的）溢出包装结果。</p>
<p>整型提供了一些固有方法(inherent methods)，允许程序员显式地执行包装算法。例如，<code>i32::wrapping_add</code> 提供了使用二进制补码溢出约定算法的加法，即包装类加法(wrapping addition)。</p>
<p>标准库还提供了一个 <code>Wrapping&lt;T&gt;</code> 的新类型，该类型确保 <code>T</code> 的所有标准算术操作都具有包装语义。</p>
<p>请参阅 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md">RFC 560</a> 以了解错误条件、基本原理以及有关整数溢出的更多详细信息。</p>
<h5><a class="header" href="#逻辑错误logic-errors" id="逻辑错误logic-errors">逻辑错误(Logic errors)</a></h5>
<p>安全代码可能会被添加一些既不能在编译时也不能在运行时检查到的逻辑限制。如果程序打破了这样的限制，其表现可能是未指定的(unspecified)，但不会导致未定义行为(undefined behavior)。这些表现可能包括 panics、错误的结果、程序中止(aborts)和程序无法终止(non-termination)。并且这些表现在运行期、构建期或各种构建期之间的的具体表现也可能有所不同。</p>
<p>例如，同时实现 <code>Hash</code> 和 <code>Eq</code> 就要求被认为相等的值具有相等的散列。另一个例子是像 <code>BinaryHeap</code>、<code>BTreeMap</code>、<code>BTreeSet</code>、<code>HashMap</code> 和 <code>HashSet</code> 这样的数据结构，它们描述了在数据结构中修改键的约束。违反这些约束并不被认为是非安全的，但程序（在逻辑上却）被认为是错误的，其行为是不可预测的。</p>
<!-- 2021-1-16-->
<!-- checked -->
<h1><a class="header" href="#constant-evaluation" id="constant-evaluation">Constant evaluation</a></h1>
<h1><a class="header" href="#常量求值" id="常量求值">常量求值</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/const_eval.md">const_eval.md</a><br />
commit:  8425f5bad3ac40e807e3f75f13b989944da28b62 <br />
本章译文最后维护日期：2021-4-5</p>
</blockquote>
<p>常量求值是在编译过程中计算[表达式][<a href="expressions.html">expressions</a>]结果的过程。（不是所有表达式都可以在编译时求值，也就是说）只有全部表达式的某个子集可以在编译时求值。</p>
<h2><a class="header" href="#constant-expressions" id="constant-expressions">Constant expressions</a></h2>
<h2><a class="header" href="#常量表达式" id="常量表达式">常量表达式</a></h2>
<p>某些形式的表达式（被称为常量表达式）可以在编译时求值。在<a href="const_eval.html#const-context">常量(const)上下文</a>中，常量表达式是唯一允许的表达式，并且总是在编译时求值。在其他地方，比如 <a href="statements.html#let-statements">let语句</a>，常量表达式<em>可以</em>在编译时求值，但不能保证总能在此时求值。如果值必须在编译时求得（例如在常量上下文中），则像<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">数组索引</a>越界或<a href="expressions/operator-expr.html#overflow">溢出</a>这样的行为都是编译错误。如果不是必须在编译时求值，则这些行为在编译时只是警告，但它们在运行时可能会触发 panic。</p>
<p>下列表达式中，只要它们的所有操作数都是常量表达式，并且求值/计算不会引起任何 <a href="destructors.html"><code>Drop::drop</code></a>函数的运行，那这些表达式就是常量表达式。</p>
<ul>
<li><a href="expressions/literal-expr.html">字面量</a>。</li>
<li><a href="items/generics.html">常量参数</a>。</li>
<li>指向<a href="items/functions.html">函数项</a>和<a href="items/constant-items.html">常量项</a>的<a href="expressions/path-expr.html">路径</a>。不允许递归地定义常量项。</li>
<li>指向<a href="items/static-items.html">静态项</a>的路径。这种路径只允许出现在静态项的初始化器中。</li>
<li><a href="expressions/tuple-expr.html">元组表达式</a>。</li>
<li><a href="expressions/array-expr.html">数组表达式</a>。</li>
<li><a href="expressions/struct-expr.html">结构体</a>表达式。</li>
<li><a href="expressions/block-expr.html">块表达式</a>，包括非安全(<code>unsafe</code>)块。
<ul>
<li><a href="statements.html#let-statements">let语句</a>以及类似这样的不可反驳型<a href="patterns.html">模式</a>绑定，包括可变绑定。</li>
<li><a href="expressions/operator-expr.html#assignment-expressions">赋值表达式</a></li>
<li><a href="expressions/operator-expr.html#compound-assignment-expressions">复合赋值表达式</a></li>
<li><a href="statements.html#expression-statements">表达式语句</a></li>
</ul>
</li>
<li><a href="expressions/field-expr.html">字段</a>表达式。</li>
<li>索引表达式，长度为 <code>usize</code> 的<a href="expressions/array-expr.html#array-and-slice-indexing-expressions">数组索引</a>或<a href="types/slice.html">切片</a>。</li>
<li><a href="expressions/range-expr.html">区间表达式</a>。</li>
<li>未从环境捕获变量的<a href="expressions/closure-expr.html">闭包</a>。</li>
<li>在整型、浮点型、布尔型(<code>bool</code>)和字符型(<code>char</code>)上做的各种内置运算，包括：<a href="expressions/operator-expr.html#negation-operators">取反</a>、<a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">算术</a>、<a href="expressions/operator-expr.html#arithmetic-and-logical-binary-operators">逻辑</a>、<a href="expressions/operator-expr.html#comparison-operators">比较</a> 或 <a href="expressions/operator-expr.html#lazy-boolean-operators">惰性布尔</a>运算。</li>
<li>排除借用类型为<a href="interior-mutability.html">内部可变借用</a>的共享<a href="expressions/operator-expr.html#borrow-operators">借用</a>表达式。</li>
<li>排除解引用裸指针的<a href="expressions/operator-expr.html#the-dereference-operator">解引用操作</a>。8425f5bad3ac40e807e3f75f13b989944da28b62
<ul>
<li>指针到地址的强制转换，</li>
<li>函数指针到地址的强制转换，和</li>
<li>到 trait对象的非固定尺寸类型强换(unsizing casts)。</li>
</ul>
</li>
<li>调用<a href="items/functions.html#const-functions">常量函数</a>和常量方法。</li>
<li><a href="expressions/loop-expr.html#infinite-loops">loop</a>, <a href="expressions/loop-expr.html#predicate-loops">while</a> 和 <a href="expressions/loop-expr.html#predicate-pattern-loops"><code>while let</code></a> 表达式。</li>
<li><a href="expressions/if-expr.html#if-expressions">if</a>, <a href="expressions/if-expr.html#if-let-expressions"><code>if let</code></a> 和 [匹配(match)] 表达式。</li>
</ul>
<h2><a class="header" href="#const-context" id="const-context">Const context</a></h2>
<h2><a class="header" href="#常量上下文" id="常量上下文">常量上下文</a></h2>
<p>下述位置是<em>常量上下文</em>：</p>
<ul>
<li><a href="types/array.html">数组类型的长度表达式</a></li>
<li><a href="expressions/array-expr.html">分号分隔的数组创建形式中的长度表达式</a></li>
<li>下述表达式的初始化器(initializer)：
<ul>
<li><a href="items/constant-items.html">常量项</a></li>
<li><a href="items/static-items.html">静态项</a></li>
<li><a href="items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations">枚举判别值</a></li>
</ul>
</li>
<li><a href="items/generics.html#const-generics">常量型泛型实参</a></li>
</ul>
<h2><a class="header" href="#const-functions-1" id="const-functions-1">Const Functions</a></h2>
<h2><a class="header" href="#常量函数-1" id="常量函数-1">常量函数</a></h2>
<p>*常量函数(const fn)*可以在常量上下文中调用。给一个函数加一个常量(<code>const</code>)标志对该函数的任何现有的使用都没有影响，它只限制参数和返回可以使用的类型，并防止在这两个位置上使用不被允许的表达式类型。程序员可以自由地用常量函数去做任何用常规函数能做的事情。</p>
<p>当从常量上下文中调用这类函数时，编译器会在编译时解释该函数。这种解释发生在编译目标环境中，而不是在当前主机环境中。因此，如果是针对一个 <code>32</code> 位目标系统进行编译，那么 <code>usize</code> 就是 <code>32</code> 位，这与在一个 <code>64</code> 位还是在一个 <code>32</code> 位主机环境中进行编译动作无关。</p>
<p>常量函数有各种限制以确保其可以在编译时可被求值。因此，例如，不可以将随机数生成器编写为常量函数。在编译时调用常量函数将始终产生与运行时调用它相同的结果，即使多次调用也是如此。这个规则有一个例外：如果在极端情况下执行复杂的浮点运算，那么可能得到（非常轻微）不同的结果。建议不要让数组长度和枚举判别值/式依赖于浮点计算。</p>
<p>常量上下文有，但常量函数不具备的显著特性有：</p>
<ul>
<li>浮点运算
<ul>
<li>（在常量函数中，）处理浮点值就像处理只有 <code>Copy</code> trait约束的泛型参数一样，不能用它们做任何事，只能复制/移动它们。</li>
</ul>
</li>
<li>trait对象(<code>dyn Trait</code>)/动态分发类型</li>
<li>泛型参数上除 <code>Sized</code> 之外的泛型约束</li>
<li>比较裸指针</li>
<li>访问联合体字段</li>
<li>调用 <a href="https://doc.rust-lang.org/std/mem/fn.transmute.html"><code>transmute</code></a>。</li>
</ul>
<p>相反，以下情况在常量函数中是有可能的，但在常量上下文中则不可能：</p>
<ul>
<li>使用泛型类型和生存期参数。
<ul>
<li>常量上下文允许有限地使用<a href="items/generics.html#const-generics">常量型泛型形参</a>。</li>
</ul>
</li>
</ul>
<h1><a class="header" href="#application-binary-interface-abi" id="application-binary-interface-abi">Application Binary Interface (ABI)</a></h1>
<h1><a class="header" href="#应用程序二进制接口abi" id="应用程序二进制接口abi">应用程序二进制接口(ABI)</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/abi.md">abi.md.md</a><br />
commit:  e773318a837092d7b5276bbeaf9fda06cca61cee <br />
本章译文最后维护日期：2021-1-16</p>
</blockquote>
<p>本节介绍影响 crate 编译输出的 ABI 的各种特性。</p>
<p>有关为导出函数(exporting functions)指定 ABI 的信息，请参阅<a href="items/functions.html#extern-function-qualifier"><em>外部函数</em></a>。参阅[<em>外部块</em>]]<a href="items/external-blocks.html">external blocks</a>了解关于指定 ABI 来链接外部库的信息。</p>
<h2><a class="header" href="#the-used-attribute" id="the-used-attribute">The <code>used</code> attribute</a></h2>
<h2><a class="header" href="#used属性" id="used属性"><code>used</code>属性</a></h2>
<p><em><code>used</code>属性</em>只能用在<a href="items/static-items.html">静态(<code>static</code>)项</a>上。此<a href="attributes.html">属性</a>强制编译器将该变量保留在输出对象文件中(.o、.rlib 等，不包括最终的二进制文件)，即使该变量没有被 crate 中的任何其他项使用或引用。注意，链接器(linker)仍有权移除此类变量。</p>
<p>下面的示例显示了编译器在什么条件下在输出对象文件中保留静态(<code>static</code>)项。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// foo.rs

// 将保留，因为 `#[used]`:
#[used]
static FOO: u32 = 0;

// 可移除，因为没实际使用:
#[allow(dead_code)]
static BAR: u32 = 0;

// 将保留，因为这个是公有的:
pub static BAZ: u32 = 0;

// 将保留，因为这个被可达公有函数引用:
static QUUX: u32 = 0;

pub fn quux() -&gt; &amp;'static u32 {
    &amp;QUUX
}

// 可移除，因为被私有且未被使用的函数引用:
static CORGE: u32 = 0;

#[allow(dead_code)]
fn corge() -&gt; &amp;'static u32 {
    &amp;CORGE
}
<span class="boring">}
</span></code></pre></pre>
<pre><code class="language-console">$ rustc -O --emit=obj --crate-type=rlib foo.rs

$ nm -C foo.o
0000000000000000 R foo::BAZ
0000000000000000 r foo::FOO
0000000000000000 R foo::QUUX
0000000000000000 T foo::quux
</code></pre>
<h2><a class="header" href="#the-no_mangle-attribute" id="the-no_mangle-attribute">The <code>no_mangle</code> attribute</a></h2>
<h2><a class="header" href="#no_mangle属性" id="no_mangle属性"><code>no_mangle</code>属性</a></h2>
<p>可以在任何<a href="items.html">程序项</a>上使用 <em><code>no_mangle</code>属性</em>来禁用标准名称符号名混淆(standard symbol name mangling)。禁用此功能后，此程序项的导出符号(symbol)名将直接是此程序项的原来的名称标识符。</p>
<p>此外，就跟<a href="abi.html#the-used-attribute"><code>used</code>属性</a>一样，此属性修饰的程序项也将从生成的库或对象文件中公开导出。</p>
<h2><a class="header" href="#the-link_section-attribute" id="the-link_section-attribute">The <code>link_section</code> attribute</a></h2>
<h2><a class="header" href="#link_section属性" id="link_section属性"><code>link_section</code>属性</a></h2>
<p><code>link_section</code>属性指定了输出对象文件中<a href="items/functions.html">函数</a>或<a href="items/static-items.html">静态项</a>的内容将被放置到的节点位置。它使用 <a href="attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法指定节点名称。</p>
<!-- no_run: don't link. The format of the section name is platform-specific. -->
<pre><pre class="playground"><code class="language-rust no_run edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[no_mangle]
#[link_section = &quot;.example_section&quot;]
pub static VAR1: u32 = 1;
<span class="boring">}
</span></code></pre></pre>
<h2><a class="header" href="#the-export_name-attribute" id="the-export_name-attribute">The <code>export_name</code> attribute</a></h2>
<h2><a class="header" href="#export_name属性" id="export_name属性"><code>export_name</code>属性</a></h2>
<p><em><code>export_name</code>属性</em>指定将在<a href="items/functions.html">函数</a>或<a href="items/static-items.html">静态项</a>上导出的符号的名称。它使用 <a href="attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法指定符号名。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#[export_name = &quot;exported_symbol_name&quot;]
pub fn name_in_rust() { }
<span class="boring">}
</span></code></pre></pre>
<!-- 2021-1-16-->
<!-- checked -->
<h1><a class="header" href="#the-rust-runtime" id="the-rust-runtime">The Rust runtime</a></h1>
<h1><a class="header" href="#rust运行时" id="rust运行时">Rust运行时</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/abi.md">abi.md.md</a><br />
commit:  f8e76ee9368f498f7f044c719de68c7d95da9972 <br />
本章译文最后维护日期：2020-11-3</p>
</blockquote>
<p>本节介绍 Rust运行时的某些方面的特性。</p>
<h2><a class="header" href="#the-panic_handler-attribute" id="the-panic_handler-attribute">The <code>panic_handler</code> attribute</a></h2>
<h2><a class="header" href="#panic_handler属性" id="panic_handler属性"><code>panic_handler</code>属性</a></h2>
<p><em><code>panic_handler</code>属性</em>只能应用于签名为 <code>fn(&amp;PanicInfo) -&gt; !</code> 的函数。有此<a href="attributes.html">属性</a>标记的函数定义了 panic 的行为。核心库内的结构体 <a href="https://doc.rust-lang.org/core/panic/struct.PanicInfo.html"><code>PanicInfo</code></a> 可以收集 panic 发生点的一些信息。在二进制、dylib 或 cdylib 类型的 crate 的依赖关系图(dependency graph)中必须有一个<code>panic_handler</code> 函数。</p>
<p>下面展示了一个 <code>panic_handler</code> 函数，它记录(log) panic 消息，然后终止(halts)线程。</p>
<!-- ignore: test infrastructure can't handle no_std -->
<pre><code class="language-rust ignore">#![no_std]

use core::fmt::{self, Write};
use core::panic::PanicInfo;

struct Sink {
    // ..
<span class="boring">   _0: (),
</span>}
<span class="boring">
</span><span class="boring">impl Sink {
</span><span class="boring">    fn new() -&gt; Sink { Sink { _0: () }}
</span><span class="boring">}
</span><span class="boring">
</span><span class="boring">impl fmt::Write for Sink {
</span><span class="boring">    fn write_str(&amp;mut self, _: &amp;str) -&gt; fmt::Result { Ok(()) }
</span><span class="boring">}
</span>
#[panic_handler]
fn panic(info: &amp;PanicInfo) -&gt; ! {
    let mut sink = Sink::new();

    // logs &quot;panicked at '$reason', src/main.rs:27:4&quot; to some `sink`
    let _ = writeln!(sink, &quot;{}&quot;, info);

    loop {}
}
</code></pre>
<h3><a class="header" href="#standard-behavior" id="standard-behavior">Standard behavior</a></h3>
<h3><a class="header" href="#标准行为" id="标准行为">标准行为</a></h3>
<p>标准库提供了 <code>panic_handler</code> 的一个实现，它的默认设置是展开堆栈，但也可以<a href="https://doc.rust-lang.org/book/ch09-01-unrecoverable-errors-with-panic.html">更改为中止(abort)进程</a>。标准库的 panic 行为可以使用 <a href="https://doc.rust-lang.org/std/panic/fn.set_hook.html">set_hook</a> 函数在运行时里去修改。</p>
<h2><a class="header" href="#the-global_allocator-attribute" id="the-global_allocator-attribute">The <code>global_allocator</code> attribute</a></h2>
<h2><a class="header" href="#global_allocator属性" id="global_allocator属性"><code>global_allocator</code>属性</a></h2>
<p>在实现 <a href="https://doc.rust-lang.org/alloc/alloc/trait.GlobalAlloc.html"><code>GlobalAlloc</code></a> trait 的<a href="items/static-items.html">静态项</a>上使用 <em><code>global_allocator</code>属性</em>来设置全局分配器。</p>
<h2><a class="header" href="#the-windows_subsystem-attribute" id="the-windows_subsystem-attribute">The <code>windows_subsystem</code> attribute</a></h2>
<h2><a class="header" href="#windows_subsystem属性" id="windows_subsystem属性"><code>windows_subsystem</code>属性</a></h2>
<p>当为一个 Windows 编译目标配置链接属性时，<em><code>windows_subsystem</code>属性</em>可以用来在 crate 级别上配置<a href="https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx">子系统(subsystem)</a>类别。它使用 <a href="attributes.html#meta-item-attribute-syntax"><em>MetaNameValueStr</em></a>元项属性句法用 <code>console</code> 或 <code>windows</code> 两个可行值指定子系统。对于非windows 编译目标和非二进制的 <a href="linkage.html">crate类型</a>，该属性将被忽略。</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span>#![windows_subsystem = &quot;windows&quot;]
<span class="boring">fn main() {
</span><span class="boring">}
</span></code></pre></pre>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#appendices" id="appendices">Appendices</a></h1>
<h1><a class="header" href="#附录" id="附录">附录</a></h1>
<h1><a class="header" href="#appendixmacro-follow-set-ambiguity-formal-specification" id="appendixmacro-follow-set-ambiguity-formal-specification">Appendix：Macro Follow-Set Ambiguity Formal Specification</a></h1>
<h1><a class="header" href="#附录关于宏随集的二义性的形式化规范" id="附录关于宏随集的二义性的形式化规范">附录：关于宏随集的二义性的形式化规范</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/macro-ambiguity.md">macro-ambiguity.md</a><br />
commit:  6ee9fc95ac3b7df8a01079e13280a283a7a24612 <br />
本章译文最后维护日期：2021-07-11</p>
</blockquote>
<p>本文介绍了下述<a href="macros-by-example.html">声明宏</a>规则的正式规范。它们最初是在 <a href="https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md">RFC 550</a> 中指定的（本文的大部分内容都是从其中复制过来的），并在后续的 RFC 中进行了进一步的展开论述。</p>
<h2><a class="header" href="#definitions--conventions" id="definitions--conventions">Definitions &amp; Conventions</a></h2>
<h2><a class="header" href="#定义和约定" id="定义和约定">定义和约定</a></h2>
<ul>
<li><code>macro</code>：宏，源代码中任何可调用的类似 <code>foo!(...)</code> 的东西。</li>
<li><code>MBE</code>：macro-by-example，声明宏，由 <code>macro_rules</code> 定义的宏。</li>
<li><code>matcher</code>：匹配器，<code>macro_rules</code>调用中一条规则的左侧部分，或其子部分(subportion)。（译者注：子部分的意思是匹配器可嵌套，可相互包含）</li>
<li><code>macro parser</code>：宏解释器，Rust 解析器中的一段程序，这段程序使用从所有命中的匹配器中推导出的文法规则来解析宏输入。</li>
<li><code>fragment</code>：匹配段，给定匹配器将接受（或“匹配”）的 Rust 句法对象。</li>
<li><code>repetition</code> ：重复元，遵循正则重复模式的匹配段。</li>
<li><code>NT</code>：non-terminal，非终结符，可以出现在匹配器中的各种“元变量”或重复元匹配器，在声明宏(MBE)句法中用前导字符 <code>$</code> 标明。</li>
<li><code>simple NT</code>：简单NT，“元变量”类型的非终结符（下面会进一步讨论）。</li>
<li><code>complex NT</code>：复杂NT，重复元类型的非终结符，通过重复元操作符（<code>*</code>, <code>+</code>, <code>?</code>）指定重复次数。 <!-- a repetition matching non-terminal, specified via repetition operators (`*`, `+`, `?`). --></li>
<li><code>token</code>：匹配器中不可再细分的元素；例如，标识符、操作符、开/闭定界符<em>和</em>简单NT(simple NT)。</li>
<li><code>token tree</code>：token树，token树由 token(叶)、复杂NT 和子token树（token树的有限序列）组成的树形数据结构。</li>
<li><code>delimiter token</code>：定界符，一种用于划分一个匹配段的结束和下一个匹配段的开始的 token。</li>
<li><code>separator token</code>：分隔符，复杂NT 中的可选定界符，用在重复元里以分隔元素。</li>
<li><code>separated complex NT</code>：带分隔符的复杂NT，分隔符是重复元的一部分的复杂NT。</li>
<li><code>delimited sequence</code>：有界序列，在序列的开始和结束处使用了适当的开闭定界符的 token树。</li>
<li><code>empty fragment</code>：空匹配段，一种不可见的 Rust 句法对象，它分割各种 token，例如空白符(whitespace)或者（在某些词法上下文中的）空标记序列。</li>
<li><code>fragment specifier</code>：匹配段选择器，简单NT 中的后段标识符部分，指定 NT 接受哪种类型的匹配段。<!-- The identifier in a simple NT that specifies which fragment the NT accepts. tobemodify--></li>
<li><code>language</code>：与上下文无关的语言。</li>
</ul>
<p>示例：</p>
<pre><pre class="playground"><code class="language-rust compile_fail edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>macro_rules! i_am_an_mbe {
    (start $foo:expr $($i:ident),* end) =&gt; ($foo)
}
<span class="boring">}
</span></code></pre></pre>
<p><code>(start $foo:expr $($i:ident),* end)</code> 是一个匹配器(matcher)。整个匹配器是一段有界字符序列（使用开闭定界符 <code>(</code> 和 <code>)</code> 界定），<code>$foo</code> 和 <code>$i</code> 是简单NT(simple NT)， <code>expr</code> 和 <code>ident</code> 是它们各自的匹配段选择器(fragment specifiers)。</p>
<p><code>$(i:ident),*</code> <em>也</em>是一个 NT；它是一个复杂NT，匹配那些被逗号分隔成的标识符类型的重复元。<code>,</code> 是这个复杂NT 的分隔符；它出现在匹配段的每对元素（如果有的话）之间。</p>
<p>复杂NT 的另一个例子是 <code>$(hi $e:expr ;)+</code>，它匹配 <code>hi &lt;expr&gt;; hi &lt;expr&gt;; ...</code> 这种格式的代码，其中 <code>hi &lt;expr&gt;;</code> 至少出现一次。注意，这种复杂NT 没有专用的分隔符。</p>
<p>(请注意，Rust 解析器会确保这类有界字符序列始终具有正确的 token树的嵌套结构以及开/闭定界符的正确匹配。)</p>
<p>下面，我们将用变量“M”表示匹配器，变量“t”和“u”表示任意单一 token，变量“tt”和“uu”表示任意 token树。（使用“tt”确实存在潜在的歧义，因为它的额外角色是一个匹配段选择器；但不用太担心，因为从上下文中，可以很清楚地看出哪个解释更符合语义）</p>
<p>用“SEP”代表分隔符，“OP”代表重复元运算符 <code>*</code>, <code>+</code>, 和 <code>?</code> “OPEN”/“CLOSE”代表包围定界字符序列的 token对（例如 <code>[</code> 和 <code>]</code> ）。</p>
<p>用希腊字母 &quot;α&quot; &quot;β&quot; &quot;γ&quot; &quot;δ&quot; 代表潜在的空token树序列。（注意没有使用希腊字母 &quot;ε&quot;，&quot;ε&quot;(epsilon)在此表示形式中代表一类特殊的角色，不代表 token树序列。）</p>
<ul>
<li>这种希腊字母约定通常只是在需要展现一段字符序列的技术细节时才被引入；特别是，当我们希望<em>强调</em>我们操作的是一个 token树序列时，我们将对该序列使用表义符 &quot;tt ...&quot;，而不是一个希腊字母。</li>
</ul>
<p>请注意，匹配器仅仅是一个 token树。如前所述，“简单NT”是一个元变量类型的 NT；因此，这是一个非重复元。例如，<code>$foo:ty</code> 是一个简单NT，而 <code>$($foo:ty)+</code> 是一个复杂NT。</p>
<p>还请注意，在这种形式体系的上下文中，术语“token”通常<em>包括</em>简单NT。</p>
<p>最后，读者要记住，根据这种形式体系的定义，简单NT 不会匹配空匹配段，因此也没有 token 会匹配 Rust句法的空匹配段。（因此，能够匹配空匹配段的 NT <em>唯有</em>复杂NT。）但这还不是全部事实，因为 <code>vis</code> 匹配器可以匹配空匹配段。因此，为了达到这种形式体系自洽统一的目的，我们将把 <code>$v:vis</code> 看作是 <code>$($v:vis)?</code>，来让匹配器匹配一个空匹配段。</p>
<h3><a class="header" href="#the-matcher-invariants" id="the-matcher-invariants">The Matcher Invariants</a></h3>
<h3><a class="header" href="#匹配器的不变式" id="匹配器的不变式">匹配器的不变式</a></h3>
<p>为了有效，匹配器必须满足以下三个不变式。注意其中 FIRST 和 FOLLOW 的定义将在后面进行描述。</p>
<ol>
<li>对于匹配器 <code>M</code> 中的任意两个连续的 token树序列（即 <code>M = ... tt uu ...</code>），并且 <code>uu ...</code> 非空，必有 FOLLOW(<code>... tt</code>) ∪ {ε} ⊇ FIRST(<code>uu ...</code>)。</li>
<li>对于匹配器中任何带分隔符的复杂NT，<code>M = ... $(tt ...) SEP OP ...</code>，必有 <code>SEP</code> ∈ FOLLOW(<code>tt ...</code>)</li>
<li>对于匹配器中不带分隔符的复杂NT，<code>M = ... $(tt ...) OP ...</code>，如果 OP = <code>*</code> 或 <code>+</code>，必有 FOLLOW(<code>tt ...</code>) ⊇ FIRST(<code>tt ...</code>)。</li>
</ol>
<p>第一个不变式表示，无论匹配器后出现什么 token（如果有的话），它都必须出现在先决随集(predetermined follow set)中的某个地方。这将确保合法的宏定义将继续对 <code>... tt</code> 的结束和 <code>uu ...</code> 的开始执行相同的判定(determination)，即使将来语言中添加了新的句法形式。
The first invariant says that whatever actual token that comes after a matcher, if any, must be somewhere in the predetermined follow set. This ensures that a legal macro definition will continue to assign the same determination as to where <code>... tt</code> ends and <code>uu ...</code> begins, even as new syntactic forms are added to the language.</p>
<p>第二个不变式表示一个带分隔符的复杂NT 必须使用一个分隔符，它是 NT 的内部内容的先决随集的一部分。这将确保合法的宏定义将继续将输入匹配段解析成相同的定界字符序列 <code>tt ...</code>，即使在将来语言中添加了新的语法形式。
The second invariant says that a separated complex NT must use a separator token that is part of the predetermined follow set for the internal contents of the NT. This ensures that a legal macro definition will continue to parse an input fragment into the same delimited sequence of <code>tt ...</code>'s, even as new syntactic forms are added to the language.</p>
<p>第三个不变式说的是，当我们有一个复杂NT，它可以匹配同一字符序列的两个或多个副本，并且两者之间没有分隔符，那么根据第一个不变式，它们必须可以放在一起。这个不变式还要求它们是非空的，这消除了可能出现的歧义。
The third invariant says that when we have a complex NT that can match two or more copies of the same thing with no separation in between, it must be permissible for them to be placed next to each other as per the first invariant. This invariant also requires they be nonempty, which eliminates a possible ambiguity.</p>
<p><strong>注意：由于历史疏忽和对行为的严重依赖，第三个不变式目前没有被执行。目前还没有决定下一步该怎么做。不遵循这个不变式的宏可能会在未来的 Rust版本中失效。参见<a href="https://github.com/rust-lang/rust/issues/56575">跟踪问题</a></strong>
<strong>NOTE：The third invariant is currently unenforced due to historical oversight and significant reliance on the behaviour. It is currently undecided what to do about this going forward. Macros that do not respect the behaviour may become invalid in a future edition of Rust. See the <a href="https://github.com/rust-lang/rust/issues/56575">tracking issue</a>.</strong></p>
<h3><a class="header" href="#first-and-follow-informally" id="first-and-follow-informally">FIRST and FOLLOW, informally</a></h3>
<h3><a class="header" href="#非正式的-first集合和-follow集合定义" id="非正式的-first集合和-follow集合定义">非正式的 FIRST集合和 FOLLOW集合定义</a></h3>
<p>给定匹配器 M 映射到三个集合：FIRST(M)，LAST(M) 和 FOLLOW(M)。
A given matcher M maps to three sets：FIRST(M), LAST(M) and FOLLOW(M).</p>
<p>这三个集合中的每一个都是由一组 token 组成的。FIRST(M) 和 LAST(M) 也可能包含一个可区分的非token元素 ε (&quot;epsilon&quot;)，这表示 M 可以匹配空匹配段。（但是 FOLLOW(M) 始终只是一组 token。）
Each of the three sets is made up of tokens. FIRST(M) and LAST(M) may also contain a distinguished non-token element ε (&quot;epsilon&quot;), which indicates that M can match the empty fragment. (But FOLLOW(M) is always just a set of tokens.)</p>
<p>非正式定义(Informally)：</p>
<ul>
<li>
<p>FIRST(M)：收集匹配段与 M 匹配时可能首先使用的 token。collects the tokens potentially used first when matching a fragment to M.</p>
</li>
<li>
<p>LAST(M)：收集匹配段与 M 匹配时可能最后使用的 token。collects the tokens potentially used last when matching a fragment to M.</p>
</li>
<li>
<p>FOLLOW(M)：允许紧跟在由 M 匹配的某个匹配段之后的 token集合。the set of tokens allowed to follow immediately after some fragment matched by M.</p>
<p>换言之：t ∈ FOLLOW(M) 当且仅当存在（可能为空的）token序列 α、β、γ、δ，其中：</p>
<ul>
<li>M 匹配 β，</li>
<li>t 与 γ 匹配，并且</li>
<li>连结 α β γ δ 是一段可解析的 Rust程序。
In other words：t ∈ FOLLOW(M) if and only if there exists (potentially empty) token sequences α, β, γ, δ where:</li>
<li>M matches β,</li>
<li>t matches γ, and</li>
<li>The concatenation α β γ δ is a parseable Rust program.</li>
</ul>
</li>
</ul>
<p>我们使用简写的 ANYTOKEN 来表示所有 token（包括简单NT）的集合。例如，如果任何 token 在匹配器 M 之后都是合法的，那么 FOLLOW(M) = ANYTOKEN。
We use the shorthand ANYTOKEN to denote the set of all tokens (including simple NTs). For example, if any token is legal after a matcher M, then FOLLOW(M) = ANYTOKEN.</p>
<p>（为了加深对上述非正式定义描述的理解，读者在阅读正式定义之前，可以先在这里读一遍后面 [关于 FIRST 和 LAST 的示例](#examples-of FIRST -and- LAST)。）
(To review one's understanding of the above informal descriptions, the reader at this point may want to jump ahead to the <a href="macro-ambiguity.html#examples-of-first-and-last">examples of FIRST/LAST</a> before reading their formal definitions.)</p>
<h3><a class="header" href="#first-last" id="first-last">FIRST, LAST</a></h3>
<p>下面是对 FIRST 和 LAST 的正式归纳定义(formal inductive definitions)。</p>
<p>“A∪B”表示集合并集，“A∩B”表示集合交集，“A\B”表示集合差集（即存在于A中，且不存在于B中的所有元素的集合）。</p>
<h4><a class="header" href="#first" id="first">FIRST</a></h4>
<p>FIRST(M) 是通过对序列 M 及其第一个 token树(如果有的话)的结构进行案例分析来定义的:
FIRST(M) is defined by case analysis on the sequence M and the structure of its first token-tree (if any):</p>
<ul>
<li>
<p>如果 M 为空序列，则 FIRST(M) = { ε }，if M is the empty sequence, then FIRST(M) = { ε },</p>
</li>
<li>
<p>如果 M 以 token t 开始，则 FIRST(M) = { t }，if M starts with a token t, then FIRST(M) = { t },</p>
<p>（注意:这涵盖了这样一种情况：M 以一个定界的token树序列开始，<code>M = OPEN tt ... CLOSE ...</code>，此时 <code>t = OPEN</code>，因此 FIRST(M) = { <code>OPEN</code> }。）
(Note：this covers the case where M starts with a delimited token-tree sequence, <code>M = OPEN tt ... CLOSE ...</code>, in which case <code>t = OPEN</code> and thus FIRST(M) = { <code>OPEN</code> }.)</p>
<p>（注意：这主要依赖于没有简单NT与空匹配段匹配这一特性。）
(Note：this critically relies on the property that no simple NT matches the empty fragment.)</p>
</li>
<li>
<p>否则，M 是一个以复杂NT开始的token树序列：<code>M = $( tt ... ) OP α</code>，或 <code>M = $( tt ... ) SEP OP α</code>，(其中 <code>α</code> 是匹配器其余部分的token树序列(可能是空的))。Otherwise, M is a token-tree sequence starting with a complex NT：<code>M = $( tt ... ) OP α</code>, or <code>M = $( tt ... ) SEP OP α</code>, (where <code>α</code> is the (potentially empty) sequence of token trees for the rest of the matcher).</p>
<ul>
<li>Let SEP_SET(M) = { SEP } 如果存在 SEP 且 ε ∈ FIRST(<code>tt ...</code>)；否则 SEP_SET(M) = {}。</li>
</ul>
</li>
<li>
<p>Let ALPHA_SET(M) = FIRST(<code>α</code>) if OP = <code>*</code> or <code>?</code> and ALPHA_SET(M) = {} if OP = <code>+</code>.</p>
</li>
<li>
<p>FIRST(M) = (FIRST(<code>tt ...</code>) \ {ε}) ∪ SEP_SET(M) ∪ ALPHA_SET(M).</p>
</li>
</ul>
<p>复杂NT 的定义值得商榷。SEP_SET(M) 定义了分隔符可能是 M 的第一个有效token的可能性，当定义了分隔符且重复匹配段可能为空时，就会发生这种情况。ALPHA_SET(M)定义了复杂NT可能为空的可能性，这意味着 M 的第一个有效token集合是后继token树序列 <code>α</code> 。当使用了操作符 <code>*</code> 或 <code>?</code> 时，这种情况下可能没有重复元。理论上，如果 <code>+</code> 与一个可能为空的重复匹配段一起使用，也会出现这种情况，但是第三个不变式禁止这样做。
The definition for complex NTs deserves some justification. SEP_SET(M) defines the possibility that the separator could be a valid first token for M, which happens when there is a separator defined and the repeated fragment could be empty. ALPHA_SET(M) defines the possibility that the complex NT could be empty, meaning that M's valid first tokens are those of the following token-tree sequences <code>α</code>. This occurs when either <code>*</code> or <code>?</code> is used, in which case there could be zero repetitions. In theory, this could also occur if <code>+</code> was used with a potentially-empty repeating fragment, but this is forbidden by the third invariant.</p>
<p>From there, clearly FIRST(M) can include any token from SEP_SET(M) or ALPHA_SET(M), and if the complex NT match is nonempty, then any token starting FIRST(<code>tt ...</code>) could work too. The last piece to consider is ε. SEP_SET(M) and FIRST(<code>tt ...</code>) \ {ε} cannot contain ε, but ALPHA_SET(M) could. Hence, this definition allows M to accept ε if and only if ε ∈ ALPHA_SET(M) does. This is correct because for M to accept ε in the complex NT case, both the complex NT and α must accept it. If OP = <code>+</code>, meaning that the complex NT cannot be empty, then by definition ε ∉ ALPHA_SET(M). Otherwise, the complex NT can accept zero repetitions, and then ALPHA_SET(M) = FOLLOW(<code>α</code>). So this definition is correct with respect to \varepsilon as well.</p>
<h4><a class="header" href="#last" id="last">LAST</a></h4>
<p>LAST(M), defined by case analysis on M itself (a sequence of token-trees):</p>
<ul>
<li>
<p>if M is the empty sequence, then LAST(M) = { ε }</p>
</li>
<li>
<p>if M is a singleton token t, then LAST(M) = { t }</p>
</li>
<li>
<p>if M is the singleton complex NT repeating zero or more times, <code>M = $( tt ... ) *</code>, or <code>M = $( tt ... ) SEP *</code></p>
<ul>
<li>
<p>Let sep_set = { SEP } if SEP present; otherwise sep_set = {}.</p>
</li>
<li>
<p>if ε ∈ LAST(<code>tt ...</code>) then LAST(M) = LAST(<code>tt ...</code>) ∪ sep_set</p>
</li>
<li>
<p>otherwise, the sequence <code>tt ...</code> must be non-empty; LAST(M) = LAST(<code>tt ...</code>) ∪ {ε}.</p>
</li>
</ul>
</li>
<li>
<p>if M is the singleton complex NT repeating one or more times, <code>M = $( tt ... ) +</code>, or <code>M = $( tt ... ) SEP +</code></p>
<ul>
<li>
<p>Let sep_set = { SEP } if SEP present; otherwise sep_set = {}.</p>
</li>
<li>
<p>if ε ∈ LAST(<code>tt ...</code>) then LAST(M) = LAST(<code>tt ...</code>) ∪ sep_set</p>
</li>
<li>
<p>otherwise, the sequence <code>tt ...</code> must be non-empty; LAST(M) = LAST(<code>tt ...</code>)</p>
</li>
</ul>
</li>
<li>
<p>if M is the singleton complex NT repeating zero or one time, <code>M = $( tt ...) ?</code>, then LAST(M) = LAST(<code>tt ...</code>) ∪ {ε}.</p>
</li>
<li>
<p>if M is a delimited token-tree sequence <code>OPEN tt ... CLOSE</code>, then LAST(M) =
{ <code>CLOSE</code> }.</p>
</li>
<li>
<p>if M is a non-empty sequence of token-trees <code>tt uu ...</code>,</p>
<ul>
<li>
<p>If ε ∈ LAST(<code>uu ...</code>), then LAST(M) = LAST(<code>tt</code>) ∪ (LAST(<code>uu ...</code>) \ { ε }).</p>
</li>
<li>
<p>Otherwise, the sequence <code>uu ...</code> must be non-empty; then LAST(M) =
LAST(<code>uu ...</code>).</p>
</li>
</ul>
</li>
</ul>
<h3><a class="header" href="#examples-of-first-and-last" id="examples-of-first-and-last">Examples of FIRST and LAST</a></h3>
<h3><a class="header" href="#关于-first-和-last-的示例" id="关于-first-和-last-的示例">关于 FIRST 和 LAST 的示例</a></h3>
<p>下面是一些关于 FIRST 和 LAST 的例子。（请特别注意，特殊元素 ε 是如何根据输入匹配段之间的相互作用来引入和消除的。）
Below are some examples of FIRST and LAST. (Note in particular how the special ε element is introduced and eliminated based on the interaction between the pieces of the input.)</p>
<p>我们的第一个例子以树状结构呈现，以详细说明匹配器的分析是如何组成的。（一些较简单的子树已被删除。）
Our first example is presented in a tree structure to elaborate on how the analysis of the matcher composes. (Some of the simpler subtrees have been elided.)</p>
<pre><code class="language-text">INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
            ~~~~~~~~   ~~~~~~~                ~
                |         |                   |
FIRST：  { $d:ident }  { $e:expr }          { h }


INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+
            ~~~~~~~~~~~~~~~~~~             ~~~~~~~           ~~~
                        |                      |               |
FIRST：         { $d:ident }               { h, ε }         { f }

INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~    ~~~~~~~~~~~~~~    ~~~~~~~~~   ~
                        |                       |              |       |
FIRST：       { $d:ident, ε }            {  h, ε, ;  }      { f }   { g }


INPUT： $(  $d:ident   $e:expr   );*    $( $( h )* );*    $( f ; )+   g
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                        |
FIRST：                      { $d:ident, h, ;,  f }
</code></pre>
<p>Thus:</p>
<ul>
<li>FIRST(<code>$($d:ident $e:expr );* $( $(h)* );* $( f ;)+ g</code>) = { <code>$d:ident</code>, <code>h</code>, <code>;</code>, <code>f</code> }</li>
</ul>
<p>Note however that:</p>
<ul>
<li>FIRST(<code>$($d:ident $e:expr );* $( $(h)* );* $($( f ;)+ g)*</code>) = { <code>$d:ident</code>, <code>h</code>, <code>;</code>, <code>f</code>, ε }</li>
</ul>
<p>Here are similar examples but now for LAST.</p>
<ul>
<li>LAST(<code>$d:ident $e:expr</code>) = { <code>$e:expr</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );*</code>) = { <code>$e:expr</code>, ε }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)*</code>) = { <code>$e:expr</code>, ε, <code>h</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)* $( f ;)+</code>) = { <code>;</code> }</li>
<li>LAST(<code>$( $d:ident $e:expr );* $(h)* $( f ;)+ g</code>) = { <code>g</code> }</li>
</ul>
<h3><a class="header" href="#followm" id="followm">FOLLOW(M)</a></h3>
<p>Finally, the definition for FOLLOW(M) is built up as follows. pat, expr, etc.
represent simple nonterminals with the given fragment specifier.</p>
<ul>
<li>
<p>FOLLOW(pat) = {<code>=&gt;</code>, <code>,</code>, <code>=</code>, <code>|</code>, <code>if</code>, <code>in</code>}`.</p>
</li>
<li>
<p>FOLLOW(expr) = FOLLOW(stmt) =  {<code>=&gt;</code>, <code>,</code>, <code>;</code>}`.</p>
</li>
<li>
<p>FOLLOW(ty) = FOLLOW(path) = {<code>{</code>, <code>[</code>, <code>,</code>, <code>=&gt;</code>, <code>:</code>, <code>=</code>, <code>&gt;</code>, <code>&gt;&gt;</code>, <code>;</code>,
<code>|</code>, <code>as</code>, <code>where</code>, block nonterminals}.</p>
</li>
<li>
<p>FOLLOW(vis) = {<code>,</code>l any keyword or identifier except a non-raw <code>priv</code>; any
token that can begin a type; ident, ty, and path nonterminals}.</p>
</li>
<li>
<p>FOLLOW(t) = ANYTOKEN for any other simple token, including block, ident,
tt, item, lifetime, literal and meta simple nonterminals, and all terminals.</p>
</li>
<li>
<p>FOLLOW(M), for any other M, is defined as the intersection, as t ranges over
(LAST(M) \ {ε}), of FOLLOW(t).</p>
</li>
</ul>
<p>The tokens that can begin a type are, as of this writing, {<code>(</code>, <code>[</code>, <code>!</code>, <code>*</code>,
<code>&amp;</code>, <code>&amp;&amp;</code>, <code>?</code>, lifetimes, <code>&gt;</code>, <code>&gt;&gt;</code>, <code>::</code>, any non-keyword identifier, <code>super</code>,
<code>self</code>, <code>Self</code>, <code>extern</code>, <code>crate</code>, <code>$crate</code>, <code>_</code>, <code>for</code>, <code>impl</code>, <code>fn</code>, <code>unsafe</code>,
<code>typeof</code>, <code>dyn</code>}, although this list may not be complete because people won't
always remember to update the appendix when new ones are added.</p>
<p>Examples of FOLLOW for complex M:</p>
<ul>
<li>FOLLOW(<code>$( $d:ident $e:expr )*</code>) = FOLLOW(<code>$e:expr</code>)</li>
<li>FOLLOW(<code>$( $d:ident $e:expr )* $(;)*</code>) = FOLLOW(<code>$e:expr</code>) ∩ ANYTOKEN = FOLLOW(<code>$e:expr</code>)</li>
<li>FOLLOW(<code>$( $d:ident $e:expr )* $(;)* $( f |)+</code>) = ANYTOKEN</li>
</ul>
<h3><a class="header" href="#examples-of-valid-and-invalid-matchers" id="examples-of-valid-and-invalid-matchers">Examples of valid and invalid matchers</a></h3>
<p>With the above specification in hand, we can present arguments for
why particular matchers are legal and others are not.</p>
<ul>
<li>
<p><code>($ty:ty &lt; foo ,)</code> ：illegal, because FIRST(<code>&lt; foo ,</code>) = { <code>&lt;</code> } ⊈ FOLLOW(<code>ty</code>)</p>
</li>
<li>
<p><code>($ty:ty , foo &lt;)</code> ：legal, because FIRST(<code>, foo &lt;</code>) = { <code>,</code> }  is ⊆ FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($pa:pat $pb:pat $ty:ty ,)</code> ：illegal, because FIRST(<code>$pb:pat $ty:ty ,</code>) = { <code>$pb:pat</code> } ⊈ FOLLOW(<code>pat</code>), and also FIRST(<code>$ty:ty ,</code>) = { <code>$ty:ty</code> } ⊈ FOLLOW(<code>pat</code>).</p>
</li>
<li>
<p><code>( $($a:tt $b:tt)* ; )</code> ：legal, because FIRST(<code>$b:tt</code>) = { <code>$b:tt</code> } is ⊆ FOLLOW(<code>tt</code>) = ANYTOKEN, as is FIRST(<code>;</code>) = { <code>;</code> }.</p>
</li>
<li>
<p><code>( $($t:tt),* , $(t:tt),* )</code> ：legal,  (though any attempt to actually use this macro will signal a local ambiguity error during expansion).</p>
</li>
<li>
<p><code>($ty:ty $(; not sep)* -)</code> ：illegal, because FIRST(<code>$(; not sep)* -</code>) = { <code>;</code>, <code>-</code> } is not in FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($($ty:ty)-+)</code> ：illegal, because separator <code>-</code> is not in FOLLOW(<code>ty</code>).</p>
</li>
<li>
<p><code>($($e:expr)*)</code> ：illegal, because expr NTs are not in FOLLOW(expr NT).</p>
</li>
</ul>
<h1><a class="header" href="#influences" id="influences">Influences</a></h1>
<h1><a class="header" href="#影响来源" id="影响来源">影响来源</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/influences.md">influences.md</a><br />
commit:  dc3808468e37ff4c1f663d26c491a3549a42c201 <br />
本章译文最后维护日期：2020-11-3</p>
</blockquote>
<p>Rust 并不是一种极端原创的语言，它的设计元素来源广泛。下面列出了其中一些（包括已经删除的）：</p>
<ul>
<li>SML，OCaml：代数数据类型、模式匹配、类型推断、分号语句分隔</li>
<li>C++：引用，RAII，智能指针，移动语义，单态化(monomorphization)，内存模型</li>
<li>ML Kit, Cyclone：基于区域的内存管理(region based memory management)</li>
<li>Haskell (GHC)：类型属性(typeclasses), 类型簇(type families)</li>
<li>Newsqueak, Alef, Limbo：通道，并发</li>
<li>Erlang：消息传递，线程失败，<strike>链接线程失败</strike>，<strike>轻量级并发</strike></li>
<li>Swift：可选绑定(optional bindings)</li>
<li>Scheme：卫生宏(hygienic macros)</li>
<li>C#：属性</li>
<li>Ruby：闭包句法，<strike>块句法</strike></li>
<li>NIL, Hermes：<strike>typestate</strike></li>
<li><a href="http://www.unicode.org/reports/tr31/">Unicode Annex #31</a>：标识符和模式句法</li>
</ul>
<!-- 2020-11-12-->
<!-- checked -->
<h1><a class="header" href="#glossary" id="glossary">Glossary</a></h1>
<h1><a class="header" href="#术语表" id="术语表">术语表</a></h1>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/glossary.md">glossary.md</a><br />
commit: e9862d82e92bb0d6f89df4036a98f96bcdd61c95 <br />
本章译文最后维护日期：2021-06-09</p>
</blockquote>
<h3><a class="header" href="#abstract-syntax-tree" id="abstract-syntax-tree">Abstract syntax tree</a></h3>
<h3><a class="header" href="#抽象句法树" id="抽象句法树">抽象句法树</a></h3>
<p>“抽象句法树”，或“AST”，是编译器编译程序时，程序结构的中间表示形式。<br />
An ‘abstract syntax tree’, or ‘AST’, is an intermediate representation of the structure of the program when the compiler is compiling it.</p>
<h3><a class="header" href="#alignment" id="alignment">Alignment</a></h3>
<h3><a class="header" href="#对齐量" id="对齐量">对齐量</a></h3>
<p>值的对齐量指定值的首选起始存储地址。对齐量总是2的幂次。值的引用必须是对齐的。<a href="type-layout.html#size-and-alignment">更多</a>。<br />
The alignment of a value specifies what addresses values are preferred to start at. Always a power of two. References to a value must be aligned. <a href="type-layout.html#size-and-alignment">More</a>.</p>
<h3><a class="header" href="#arity" id="arity">Arity</a></h3>
<h3><a class="header" href="#元数" id="元数">元数</a></h3>
<p>元数是指函数或运算符接受的参数个数。例如，<code>f(2, 3)</code> 和 <code>g(4, 6)</code> 的元数为2，而 <code>h(8, 2, 6)</code> 的元数为3。 <code>!</code> 运算符的元数为1。<br />
Arity refers to the number of arguments a function or operator takes. For some examples, <code>f(2, 3)</code> and <code>g(4, 6)</code> have arity 2, while <code>h(8, 2, 6)</code> has arity 3. The <code>!</code> operator has arity 1.</p>
<h3><a class="header" href="#array" id="array">Array</a></h3>
<h3><a class="header" href="#数组" id="数组">数组</a></h3>
<p>数组，有时也称为固定大小数组或内联数组，是描述关于元素集合的值，每个元素都可由程序在运行时计算的索引选择。内存模型上，数组占用连续的内存区域。<br />
An array, sometimes also called a fixed-size array or an inline array, is a value describing a collection of elements, each selected by an index that can be computed at run time by the program. It occupies a contiguous region of memory.</p>
<h3><a class="header" href="#associated-item" id="associated-item">Associated item</a></h3>
<h3><a class="header" href="#关联程序项关联项-1" id="关联程序项关联项-1">关联程序项/关联项</a></h3>
<p>关联程序项是与另一个程序项关联的程序项。关联程序项在 <a href="items/traits.html">trait</a> 中声明，在<a href="items/implementations.html">实现</a>中定义。只有函数、常量和类型别名可以作为关联程序项。它与<a href="glossary.html#free-item">自由程序项</a>形成对比。<br />
An associated item is an item that is associated with another item. Associated items are defined in <a href="items/implementations.html">implementations</a> and declared in <a href="items/traits.html">traits</a>. Only functions, constants, and type aliases can be associated. Contrast to a <a href="glossary.html#free-item">free item</a>.</p>
<h3><a class="header" href="#blanket-implementation" id="blanket-implementation">Blanket implementation</a></h3>
<h3><a class="header" href="#包覆实现" id="包覆实现">包覆实现</a></h3>
<p>指为<a href="glossary.html#uncovered-type">无覆盖类型</a>实现的任何实现。<code>impl&lt;T&gt; Foo for T</code>、<code>impl&lt;T&gt; Bar&lt;T&gt; for T</code>、<code>impl&lt;T&gt; Bar&lt;Vec&lt;T&gt;&gt; for T</code>、 和 <code>impl&lt;T&gt; Bar&lt;T&gt; for Vec&lt;T&gt;</code> 被认为是 包覆实现。但是，<code>impl&lt;T&gt; Bar&lt;Vec&lt;T&gt;&gt; for Vec&lt;T&gt;</code> 不被认为是，因为这个 <code>impl</code> 中所有的 <code>T</code> 的实例都被 <code>Vec</code> 覆盖。<br />
Any implementation where a type appears <a href="glossary.html#uncovered-type">uncovered</a>. <code>impl&lt;T&gt; Foo for T</code>, <code>impl&lt;T&gt; Bar&lt;T&gt; for T</code>, <code>impl&lt;T&gt; Bar&lt;Vec&lt;T&gt;&gt; for T</code>, and <code>impl&lt;T&gt; Bar&lt;T&gt; for Vec&lt;T&gt;</code> are considered blanket impls. However, <code>impl&lt;T&gt; Bar&lt;Vec&lt;T&gt;&gt; for Vec&lt;T&gt;</code> is not a blanket impl, as all instances of <code>T</code> which appear in this <code>impl</code> are covered by <code>Vec</code>.</p>
<h3><a class="header" href="#bound" id="bound">Bound</a></h3>
<h3><a class="header" href="#约束" id="约束">约束</a></h3>
<p>约束是对类型或 trait 的限制。例如，如果在函数的形数上设置了约束，则传递给该函数的实参的类型必须遵守该约束。<br />
Bounds are constraints on a type or trait. For example, if a bound is placed on the argument a function takes, types passed to that function must abide by that constraint.</p>
<h3><a class="header" href="#combinator" id="combinator">Combinator</a></h3>
<h3><a class="header" href="#组合子" id="组合子">组合子</a></h3>
<p>组合子是高阶函数，它的参数全是函数或之前定义的组合子。组合子利用这些函数或组合子返回的结果作为入参进行进一步的逻辑计算和输出。组合子可用于以模块化的方式管理控制流。<br />
Combinators are higher-order functions that apply only functions and earlier defined combinators to provide a result from its arguments. They can be used to manage control flow in a modular fashion.</p>
<h3><a class="header" href="#crate-2" id="crate-2">Crate</a></h3>
<p>crate 是编译和链接的最小单元。<a href="linkage.html">crate的类型</a>有多种，如常见的库或可执行文件。crate 可以链接和引用其他被称为外部crate 的库crate。crate是一个自包含的<a href="items/modules.html">模块</a>树，此树从一个未命名模块（此模块一般称为此crate的根模块）开始。crate内的[程序项]可以通过在根模块中将其标记为公有(pub)来让其对其他 crate 可见（注意在标记公有的过程中也要让此程序项的完整路径公有）。
<a href="crates-and-source-files.html">查看更多</a>。<br />
A crate is the unit of compilation and linking. There are different <a href="linkage.html">types of crates</a>, such as libraries or executables. Crates may link and refer to other library crates, called external crates. A crate has a self-contained tree of <a href="items/modules.html">modules</a>, starting from an unnamed root module called the crate root. <a href="items.html">Items</a> may be made visible to other crates by marking them as public in the crate root, including through <a href="paths.html">paths</a> of public modules.
<a href="crates-and-source-files.html">More</a>.</p>
<h3><a class="header" href="#dispatch" id="dispatch">Dispatch</a></h3>
<h3><a class="header" href="#分发" id="分发">分发</a></h3>
<p>分发是一种机制，用于确定涉及到多态性时实际运行的是哪个版本的代码。分发的两种主要形式是静态分发和动态分发。虽然 Rust 支持静态分发，但它也通过一种称为 trait对象的机制支持动态分发。<br />
Dispatch is the mechanism to determine which specific version of code is actually run when it involves polymorphism. Two major forms of dispatch are static dispatch and dynamic dispatch. While Rust favors static dispatch, it also supports dynamic dispatch through a mechanism called ‘trait objects’.</p>
<h3><a class="header" href="#dynamically-sized-type" id="dynamically-sized-type">Dynamically sized type</a></h3>
<h3><a class="header" href="#动态尺寸类型-1" id="动态尺寸类型-1">动态尺寸类型</a></h3>
<p>动态尺寸类型(DST)是一种没有静态已知尺寸或对齐量的类型。<br />
A dynamically sized type (DST) is a type without a statically known size or alignment.</p>
<h3><a class="header" href="#entity" id="entity">Entity</a></h3>
<h3><a class="header" href="#实体" id="实体">实体</a></h3>
<p><a href="names.html"><em>实体(entity)</em></a>是一种语言结构，在源程序中可以以某种方式被引用，通常是通过<a href="paths.html">路径(path)</a>。实体包括<a href="types.html">类型</a>、<a href="items.html">程序项</a>、<a href="items/generics.html">泛型参数</a>、<a href="patterns.html">变量绑定</a>、<a href="tokens.html#lifetimes-and-loop-labels">循环标签</a>、<a href="tokens.html#lifetimes-and-loop-labels">生存期</a>、<a href="expressions/field-expr.html">字段</a>、<a href="attributes.html">属性</a>和<a href="attributes/diagnostics.html#lint-check-attributes">lints</a>。<br />
An <a href="names.html"><em>entity</em></a> is a language construct that can be referred to in some way within the source program, usually via a <a href="paths.html">path</a>. Entities include <a href="types.html">types</a>, <a href="items.html">items</a>, <a href="items/generics.html">generic parameters</a>, <a href="patterns.html">variable bindings</a>, <a href="tokens.html#lifetimes-and-loop-labels">loop labels</a>, <a href="tokens.html#lifetimes-and-loop-labels">lifetimes</a>, <a href="expressions/field-expr.html">fields</a>, <a href="attributes.html">attributes</a>, and <a href="attributes/diagnostics.html#lint-check-attributes">lints</a>.</p>
<h3><a class="header" href="#expression" id="expression">Expression</a></h3>
<h3><a class="header" href="#表达式-1" id="表达式-1">表达式</a></h3>
<p>表达式是值、常量、变量、运算符/操作符和函数的组合，计算/求值结果为单个值，有或没有副作用都有可能。<br />
比如，<code>2 + (3 * 4)</code> 是一个返回值为14的表达式。<br />
An expression is a combination of values, constants, variables, operators and functions that evaluate to a single value, with or without side-effects.<br />
For example, <code>2 + (3 * 4)</code> is an expression that returns the value 14.</p>
<h3><a class="header" href="#free-item" id="free-item">Free item</a></h3>
<h3><a class="header" href="#自由程序项" id="自由程序项">自由程序项</a></h3>
<p>不是任何<a href="items/implementations.html">实现</a><a href="items.html">item</a>的成员的[程序项]，如<em>自由函数</em>或<em>自由常量</em>。自由程序项是与<a href="glossary.html#associated-item">关联程序项</a>相对的概念。<br />
An <a href="items.html">item</a> that is not a member of an <a href="items/implementations.html">implementation</a>, such as a <em>free function</em> or a <em>free const</em>. Contrast to an <a href="glossary.html#associated-item">associated item</a>.</p>
<h3><a class="header" href="#fundamental-traits" id="fundamental-traits">Fundamental traits</a></h3>
<h3><a class="header" href="#基础性trait" id="基础性trait">基础性trait</a></h3>
<p>基础性trait 就是如果为现有的类型实现它，就会为该类型带来突破性改变的 trait。比如 <code>Fn</code> 和 <code>Sized</code> 就是基础性trait。<br />
A fundamental trait is one where adding an impl of it for an existing type is a breaking change. The <code>Fn</code> traits and <code>Sized</code> are fundamental.</p>
<h3><a class="header" href="#fundamental-type-constructors" id="fundamental-type-constructors">Fundamental type constructors</a></h3>
<h3><a class="header" href="#基本类型构造器" id="基本类型构造器">基本类型构造器</a></h3>
<p>基本类型构造器是这样一种类型，在它之上实现一个 <a href="glossary.html#blanket-implementation">包覆实现</a>是一个突破性的改变。<code>&amp;</code>、<code>&amp;mut</code>、<code>Box</code>、和 <code>Pin</code> 是基本类型构造器。<br />
如果任何时候 <code>T</code> 都被认为是<a href="glossary.html#local-type">本地类型</a>，那 <code>&amp;T</code>、<code>&amp;mut T</code>、<code>Box&lt;T&gt;</code>、和 <code>Pin&lt;T&gt;</code> 也被认为是本地类型。基本类型构造器不能<a href="glossary.html#uncovered-type">覆盖</a>其他类型。任何时候使用术语“有覆盖类型”时，都默认把<code>&amp;T</code>、<code>&amp;mut T</code>、<code>Box&lt;T&gt;</code>、和<code>Pin&lt;T&gt;</code> 排除在外。<br />
A fundamental type constructor is a type where implementing a <a href="glossary.html#blanket-implementation">blanket implementation</a> over it is a breaking change. <code>&amp;</code>, <code>&amp;mut</code>, <code>Box</code>, and <code>Pin</code>  are fundamental. <br />
Any time a type <code>T</code> is considered <a href="glossary.html#local-type">local</a>, <code>&amp;T</code>, <code>&amp;mut T</code>, <code>Box&lt;T&gt;</code>, and <code>Pin&lt;T&gt;</code> are also considered local. Fundamental type constructors cannot <a href="glossary.html#uncovered-type">cover</a> other types. Any time the term &quot;covered type&quot; is used, the <code>T</code> in <code>&amp;T</code>, <code>&amp;mut T</code>, <code>Box&lt;T&gt;</code>, and <code>Pin&lt;T&gt;</code> is not considered covered.</p>
<h3><a class="header" href="#inhabited" id="inhabited">Inhabited</a></h3>
<p>如果类型具有构造函数，因此可以实例化，则该类型是 inhabited。inhabited 类型不是“空的”，因为可以有类型对应的值。与之相对的是 <a href="glossary.html#uninhabited">Uninhabited</a>。<br />
A type is inhabited if it has constructors and therefore can be instantiated. An inhabited type is not &quot;empty&quot; in the sense that there can be values of the type. Opposite of <a href="glossary.html#uninhabited">Uninhabited</a>.</p>
<h3><a class="header" href="#inherent-implementation" id="inherent-implementation">Inherent implementation</a></h3>
<h3><a class="header" href="#固有实现-1" id="固有实现-1">固有实现</a></h3>
<p>单独标称类型上的<a href="items/implementations.html">实现</a> ，注意关键字 <code>impl</code> 后直接是标称类型，而非 trait-标称类型对(trait-type pair)上的实现。<a href="items/implementations.html#inherent-implementations">更多</a>。 <br />
An <a href="items/implementations.html">implementation</a> that applies to a nominal type, not to a trait-type pair. <a href="items/implementations.html#inherent-implementations">More</a>.</p>
<h3><a class="header" href="#inherent-method" id="inherent-method">Inherent method</a></h3>
<h3><a class="header" href="#固有方法" id="固有方法">固有方法</a></h3>
<p>在<a href="items/implementations.html#inherent-implementations">固有实现</a>中而不是在 trait实现中定义的<a href="items/associated-items.html#methods">方法</a>。<br />
A <a href="items/associated-items.html#methods">method</a> defined in an <a href="items/implementations.html#inherent-implementations">inherent implementation</a>, not in a trait implementation.</p>
<h3><a class="header" href="#initialized" id="initialized">Initialized</a></h3>
<h3><a class="header" href="#初始化" id="初始化">初始化</a></h3>
<p>如果一个变量已经被分配了一个值，并且此值还没有被移动走，那此变量就被初始化了。对此变量而言，它会假设它之外的所有其他内存位置都未初始化。只有非安全Rust 可以在不初始化的情况下开辟内存新区域。<br />
A variable is initialized if it has been assigned a value and hasn't since been moved from. All other memory locations are assumed to be uninitialized. Only unsafe Rust can create such a memory without initializing it.</p>
<h3><a class="header" href="#local-trait" id="local-trait">Local trait</a></h3>
<h3><a class="header" href="#本地-trait" id="本地-trait">本地 trait</a></h3>
<p>本地 trait 是在当前 crate 中定义的 <code>trait</code>。它可以在模块局部定义，也可以是依附于其他类型参数而定义。给定 <code>trait Foo&lt;T, U&gt;</code>，<code>Foo</code> 总是本地的，不管替代 <code>T</code> 和 <code>U</code> 的类型是什么。<br />
A <code>trait</code> which was defined in the current crate. A trait definition is local or not independent of applied type arguments. Given <code>trait Foo&lt;T, U&gt;</code>, <code>Foo</code> is always local, regardless of the types substituted for <code>T</code> and <code>U</code>.</p>
<h3><a class="header" href="#turbofish" id="turbofish">Turbofish</a></h3>
<p>表达式中带有泛型参数的路径必须在左尖括号前加上一个 <code>::</code>。
这种为表达泛型而结合起来形式（<code>::&lt;&gt;</code>）看起来有些像一条鱼。
因此，在口头上就被称为 turbofish句法。<br />
Paths with generic parameters in expressions must prefix the opening brackets with a <code>::</code>.
Combined with the angular brackets for generics, this looks like a fish <code>::&lt;&gt;</code>.
As such, this syntax is colloquially referred to as turbofish syntax.</p>
<p>例如：</p>
<pre><pre class="playground"><code class="language-rust edition2018">
<span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let ok_num = Ok::&lt;_, ()&gt;(5);
let vec = [1, 2, 3].iter().map(|n| n * 2).collect::&lt;Vec&lt;_&gt;&gt;();
<span class="boring">}
</span></code></pre></pre>
<p>这里必须使用 <code>::</code>前缀，以便在逗号分隔的列表中进行多次比较时消除泛型路径可能的歧义。
参见 <a href="https://github.com/rust-lang/rust/blob/master/src/test/ui/bastion-of-the-turbofish.rs">the bastion of the turbofish</a> 中因为没有此前缀的而引起歧义的示例。<br />
This <code>::</code> prefix is required to disambiguate generic paths with multiple comparisons in a comma-separate list.
See <a href="https://github.com/rust-lang/rust/blob/master/src/test/ui/bastion-of-the-turbofish.rs">the bastion of the turbofish</a> for an example where not having the prefix would be ambiguous.</p>
<h3><a class="header" href="#local-type" id="local-type">Local type</a></h3>
<h3><a class="header" href="#本地类型" id="本地类型">本地类型</a></h3>
<p>指在当前 crate 中定义的 <code>struct</code>、<code>enum</code>、或 <code>union</code> 。本地类型不会受到类型参数的影响。<code>struct Foo</code> 被认为是本地的，但 <code>Vec&lt;Foo&gt;</code> 不是。<code>LocalType&lt;ForeignType&gt;</code> 是本地的。类型别名不影响本地性。<br />
A <code>struct</code>, <code>enum</code>, or <code>union</code> which was defined in the current crate. This is not affected by applied type arguments. <code>struct Foo</code> is considered local, but <code>Vec&lt;Foo&gt;</code> is not. <code>LocalType&lt;ForeignType&gt;</code> is local. Type aliases do not affect locality.</p>
<h3><a class="header" href="#module" id="module">Module</a></h3>
<h3><a class="header" href="#模块-1" id="模块-1">模块</a></h3>
<p>模块是容纳零个或多个<a href="items.html">程序项</a>的容器。模块以树的形式组织，从一个被称为当前crate的根或根模块的未命名的模块开始。在模块内，可使用<a href="paths.html">路径</a>来引用其他模块的程序项，但这些程序项的可见性要受到<a href="visibility-and-privacy.html">可见性规则</a>的限定。
<a href="items/modules.html">查看更多</a>。<br />
A module is a container for zero or more <a href="items.html">items</a>. Modules are organized in a tree, starting from an unnamed module at the root called the crate root or the root module. <a href="paths.html">Paths</a> may be used to refer to items from other modules, which may be restricted by <a href="visibility-and-privacy.html">visibility rules</a>.
<a href="items/modules.html">More</a></p>
<h3><a class="header" href="#name" id="name">Name</a></h3>
<h3><a class="header" href="#名称-1" id="名称-1">名称</a></h3>
<p><a href="names.html"><em>名称</em></a>是一个指向<a href="glossary.html#entity">实体</a>的<a href="identifiers.html">标识符</a>或<a href="tokens.html#lifetimes-and-loop-labels">生存期或循环标签</a>。*名称绑定(name binding)*是指实体声明时引入了与该实体相关联的标识符或标签。<a href="paths.html">路径</a>、标识符和标签用于引用实体。<br />
A <a href="names.html"><em>name</em></a> is an <a href="identifiers.html">identifier</a> or <a href="tokens.html#lifetimes-and-loop-labels">lifetime or loop label</a> that refers to an <a href="glossary.html#entity">entity</a>. A <em>name binding</em> is when an entity declaration introduces an identifier or label associated with that entity. <a href="paths.html">Paths</a>, identifiers, and labels are used to refer to an entity.</p>
<h3><a class="header" href="#name-resolution-1" id="name-resolution-1">Name resolution</a></h3>
<h3><a class="header" href="#名称解析-1" id="名称解析-1">名称解析</a></h3>
<p><a href="names/name-resolution.html"><em>名称解析</em></a>是将<a href="paths.html">路径</a>、<a href="identifiers.html">标识符</a>、<a href="tokens.html#lifetimes-and-loop-labels">标签</a>和<a href="glossary.html#entity">实体(entity)</a>声明绑定在一起的的编译过程。<br />
<a href="names/name-resolution.html"><em>Name resolution</em></a> is the compile-time process of tying <a href="paths.html">paths</a>, <a href="identifiers.html">identifiers</a>, and <a href="tokens.html#lifetimes-and-loop-labels">labels</a> to <a href="glossary.html#entity">entity</a> declarations.</p>
<h3><a class="header" href="#namespace" id="namespace">Namespace</a></h3>
<h3><a class="header" href="#命名空间-1" id="命名空间-1">命名空间</a></h3>
<p><em>命名空间</em>是基于名称所引用的<a href="glossary.html#entity">实体</a>类型的声明<a href="glossary.html#name">名称</a>的逻辑分组。命名空间让在一个命名空间中出现的名称不会与另一个命名空间中的相同名称冲突。<br />
A <em>namespace</em> is a logical grouping of declared <a href="glossary.html#name">names</a> based on the kind of <a href="glossary.html#entity">entity</a> the name refers to. Namespaces allow the occurrence of a name in one namespace to not conflict with the same name in another namespace.<br />
在命名空间中，名称统一组织在一个层次结构中，层次结构的每一层都有自己的命名实体集合。<br />
Within a namespace, names are organized in a hierarchy, where each level of the hierarchy has its own collection of named entities.</p>
<h3><a class="header" href="#nominal-types" id="nominal-types">Nominal types</a></h3>
<h3><a class="header" href="#标称类型" id="标称类型">标称类型</a></h3>
<p>可用路径直接引用的类型。具体来说就是<a href="items/enumerations.html">枚举(<code>enum</code>)</a>、<a href="items/structs.html">结构体(<code>struct</code>)</a>、<a href="items/unions.html">联合体(<code>union</code>)</a>和 <a href="types/trait-object.html">trait对象</a>。<br />
Types that can be referred to by a path directly. Specifically <a href="items/enumerations.html">enums</a>, <a href="items/structs.html">structs</a>, <a href="items/unions.html">unions</a>, and <a href="types/trait-object.html">trait objects</a>.</p>
<h3><a class="header" href="#object-safe-traits" id="object-safe-traits">Object safe traits</a></h3>
<h3><a class="header" href="#对象安全trait" id="对象安全trait">对象安全trait</a></h3>
<p>可以用作 [trait对象]的 <a href="items/traits.html">trait</a>。只有遵循特定<a href="items/traits.html#object-safety">规则</a>的 trait 才是对象安全的。<br />
<a href="items/traits.html">Traits</a> that can be used as <a href="types/trait-object.html">trait objects</a>. Only traits that follow specific <a href="items/traits.html#object-safety">rules</a> are object safe.</p>
<h3><a class="header" href="#path" id="path">Path</a></h3>
<h3><a class="header" href="#路径-1" id="路径-1">路径</a></h3>
<p><a href="paths.html"><em>路径</em></a>是一个或多个路径段组成的序列，用于引用当前作用域或某<a href="glossary.html#namespace">命名空间</a>层次结构中的<a href="glossary.html#entity">实体</a>。<br />
A <a href="paths.html"><em>path</em></a> is a sequence of one or more path segments used to refer to an <a href="glossary.html#entity">entity</a> in the current scope or other levels of a <a href="glossary.html#namespace">namespace</a> hierarchy.</p>
<h3><a class="header" href="#prelude" id="prelude">Prelude</a></h3>
<h3><a class="header" href="#预加载模块集预导入包" id="预加载模块集预导入包">预加载模块集/预导入包</a></h3>
<p>预加载模块集，或者 Rust 预加载模块集，是一个会被导入到每个 crate 中的每个模块的小型程序项集合（其中大部分是 trait）。trait 在预加载模块集中很普遍。<br />
Prelude, or The Rust Prelude, is a small collection of items - mostly traits - that are imported into every module of every crate. The traits in the prelude are pervasive.</p>
<h3><a class="header" href="#scope" id="scope">Scope</a></h3>
<h3><a class="header" href="#作用域-1" id="作用域-1">作用域</a></h3>
<p><a href="names/scopes.html"><em>作用域</em></a>是源文本的一个区域，在该区域中可以直接使用其名称来引用在其下命名的命名<a href="glossary.html#entity">实体</a>。<br />
A <a href="names/scopes.html"><em>scope</em></a> is the region of source text where a named <a href="glossary.html#entity">entity</a> may be referenced with that name.</p>
<h3><a class="header" href="#scrutinee" id="scrutinee">Scrutinee</a></h3>
<h3><a class="header" href="#检验对象检验对象表达式" id="检验对象检验对象表达式">检验对象\检验对象表达式</a></h3>
<p>检验对象是在匹配(<code>match</code>)表达式和类似的模式匹配结构上匹配的表达式。例如，在 <code>match x { A =&gt; 1, B =&gt; 2 }</code> 中，表达式 <code>x</code> 是 scrutinee。<br />
A scrutinee is the expression that is matched on in <code>match</code> expressions and similar pattern matching constructs. For example, in <code>match x { A =&gt; 1, B =&gt; 2 }</code>, the expression <code>x</code> is the scrutinee.</p>
<h3><a class="header" href="#size" id="size">Size</a></h3>
<h3><a class="header" href="#类型尺寸尺寸" id="类型尺寸尺寸">类型尺寸/尺寸</a></h3>
<p>值的尺寸有两个定义。<br />
第一个是必须分配多少内存来存储这个值。<br />
第二个是它是在具有该项类型的数组中连续元素之间的字节偏移量。<br />
它是对齐量的整数倍数，包括零倍。尺寸会根据编译器版本(进行新的优化时)和目标平台(类似于 <code>usize</code> 在不同平台上的变化)而变化。<br />
查看<a href="type-layout.html#size-and-alignment">更多</a>.
The size of a value has two definitions.<br />
The first is that it is how much memory must be allocated to store that value.<br />
The second is that it is the offset in bytes between successive elements in an array with that item type.
It is a multiple of the alignment, including zero. The size can change depending on compiler version (as new optimizations are made) and target platform (similar to how <code>usize</code> varies per-platform).</p>
<h3><a class="header" href="#slice" id="slice">Slice</a></h3>
<h3><a class="header" href="#切片" id="切片">切片</a></h3>
<p>切片是一段连续的内存序列上的具有动态尺寸视图功能的类型，写为 <code>[T]</code>。<br />
它经常以借用的形式出现，可变借用和共享借用都有可能。共享借用切片类型是 <code>&amp;[T]</code>，可变借用切片类型是 <code>&amp;mut [T]</code>，其中 <code>T</code> 表示元素类型。<br />
A slice is dynamically-sized view into a contiguous sequence, written as <code>[T]</code>.<br />
It is often seen in its borrowed forms, either mutable or shared. The shared slice type is <code>&amp;[T]</code>, while the mutable slice type is <code>&amp;mut [T]</code>, where <code>T</code> represents the element type.</p>
<h3><a class="header" href="#statement" id="statement">Statement</a></h3>
<h3><a class="header" href="#语句-1" id="语句-1">语句</a></h3>
<p>语句是编程语言中最小的独立元素，它命令计算机执行一个动作。<br />
A statement is the smallest standalone element of a programming language that commands a computer to perform an action.</p>
<h3><a class="header" href="#string-literal" id="string-literal">String literal</a></h3>
<h3><a class="header" href="#字符串字面量-1" id="字符串字面量-1">字符串字面量</a></h3>
<p>字符串字面量是直接存储在最终二进制文件中的字符串，因此在 <code>'static</code> 生存期内是有效的。<br />
它的类型是借用形式的生存期 <code>'static</code> 的字符串切片，即：<code>&amp;'static str</code>。<br />
A string literal is a string stored directly in the final binary, and so will be valid for the <code>'static</code> duration.<br />
Its type is <code>'static</code> duration borrowed string slice, <code>&amp;'static str</code>.</p>
<h3><a class="header" href="#string-slice" id="string-slice">String slice</a></h3>
<h3><a class="header" href="#字符串切片str" id="字符串切片str">字符串切片(<code>str</code>)</a></h3>
<p>字符串切片是 Rust 中最基础的字符串类型，写为 <code>str</code>。它经常以借用的形式出现，可变借用和共享借用都有可能。共享借用的字符串切片类型是  <code>&amp;str</code>，可变借用的字符串切片类型是 <code>&amp;mut str</code>。<br />
字符串切片总是有效的 UTF-8。<br />
A string slice is the most primitive string type in Rust, written as <code>str</code>. It is often seen in its borrowed forms, either mutable or shared. The shared string slice type is <code>&amp;str</code>, while the mutable string slice type is <code>&amp;mut str</code>.<br />
Strings slices are always valid UTF-8.</p>
<h3><a class="header" href="#trait-1" id="trait-1">Trait</a></h3>
<p>trait 是一种程序项，用于描述类型必须提供的功能。它允许类型对其行为做出某些承诺。<br />
泛型函数和泛型结构体可以使用 trait 来限制或约束它们所接受的类型。<br />
A trait is a language item that is used for describing the functionalities a type must provide. It allows a type to make certain promises about its behavior.<br />
Generic functions and generic structs can use traits to constrain, or bound, the types they accept.</p>
<h3><a class="header" href="#uncovered-type" id="uncovered-type">Uncovered type</a></h3>
<h3><a class="header" href="#无覆盖类型" id="无覆盖类型">无覆盖类型</a></h3>
<p>不作为其他类型的参数出现的类型。例如，<code>T</code> 就是无覆盖的，但 <code>Vec&lt;T&gt;</code> 中的 <code>T</code> 就是有覆盖的。这（种说法）只与类型参数相关。<br />
A type which does not appear as an argument to another type. For example, <code>T</code> is uncovered, but the <code>T</code> in <code>Vec&lt;T&gt;</code> is covered. This is only relevant for type arguments.</p>
<h3><a class="header" href="#undefined-behavior" id="undefined-behavior">Undefined behavior</a></h3>
<h3><a class="header" href="#未定义行为" id="未定义行为">未定义行为</a></h3>
<p>非指定的编译时或运行时行为。这可能导致，但不限于：进程终止或崩溃；不正确的、不正确的或非预定计算；或特定于平台的结果。查看<a href="behavior-considered-undefined.html">更多</a><br />
Compile-time or run-time behavior that is not specified. This may result in, but is not limited to: process termination or corruption; improper, incorrect, or unintended computation; or platform-specific results. <a href="behavior-considered-undefined.html">More</a>.</p>
<h3><a class="header" href="#uninhabited" id="uninhabited">Uninhabited</a></h3>
<p>如果类型没有构造函数，因此永远不能实例化，则该类型是 Uninhabited。一个 Uninhabited 类型是“空的”，意思是该类型没有值。Uninhabited 类型的典型例子是 <a href="types/never.html">never type</a> <code>!</code>，或不带变体的 <code>enum Never { }</code>。与之相对的是 <a href="glossary.html#inhabited">Inhabited</a>。<br />
A type is uninhabited if it has no constructors and therefore can never be instantiated. An uninhabited type is &quot;empty&quot; in the sense that there are no values of the type. The canonical example of an uninhabited type is the <a href="types/never.html">never type</a> <code>!</code>, or an enum with no variants <code>enum Never { }</code>. Opposite of <a href="glossary.html#inhabited">Inhabited</a>.</p>
<ul>
<li>alignment：对齐量、对齐值</li>
<li>annotated：标注</li>
<li>artifact：部件</li>
<li>associated constant/function：关联常量/函数</li>
<li>attribute macro：属性宏</li>
<li>the attributed function：此(属性限定的)函数</li>
<li>bare attribute：裸属性。-指没有属性值或属性列表的属性</li>
<li>block：块</li>
<li>body： 代码体</li>
<li>byte order mark: 字节序标记</li>
<li>checked：安全检查通过的
<ul>
<li>unchecked：不受安全检查的</li>
</ul>
</li>
<li>coercion：自动强转、强制转换</li>
<li>combinator：组合器</li>
<li>canonical：规范</li>
<li>constructor：构造器、构造函数</li>
<li>delimiter： 定界符</li>
<li>destructor：析构行为、析构函数</li>
<li>desugar：脱糖</li>
<li>discriminant： 判别值、判别式</li>
<li>doc comment： 文档型注解</li>
<li>dyn trait：trait对象、动态分发</li>
<li>emit：发布、扩展出（对宏展开专用）</li>
<li>endianness： 字节序</li>
<li>evaluation：求值、计算</li>
<li>feature：特性</li>
<li>field： 字段</li>
<li>final expression： 最终表达式</li>
<li>follow-set： 随集</li>
<li>fragment specifier：片段分类符</li>
<li>grammar：语法、文法</li>
<li>hygiene：卫生性</li>
<li>implementing type：实现类型</li>
<li>inherent implementation: 固有实现</li>
<li>initializer： 程序初始化器、初始化器
<ul>
<li>initializer expression： 初始化表达式</li>
</ul>
</li>
<li>irrefutable： 不可反驳型</li>
<li>item： 程序项，
<ul>
<li>associated item：关联程序项</li>
<li>constant item：常量项</li>
<li>module item：模块项</li>
<li>static item：静态项</li>
<li>trait item：trait项</li>
</ul>
</li>
<li>key: 键</li>
<li>lexer： 词法</li>
<li>lifecycle：生命周期</li>
<li>lifetime: 生存期</li>
<li>macro attribute：宏属性、属性宏（定义的）属性</li>
<li>mark、marker：标记、标记符</li>
<li>match arm： 匹配臂</li>
<li>matcher： 匹配器</li>
<li>meta item attribute：元项属性</li>
<li>monomorphization：单态化</li>
<li>namespace： 命名空间</li>
<li>nominal：标称、标称型；-就是可以使用路径来指向的
<ul>
<li>nominal type: 标称类型</li>
</ul>
</li>
<li>notation: 符号、表义符</li>
<li>never type: never类型、无返回类型</li>
<li>operator： 操作符、运算符
<ul>
<li>binary operators: 双目运算符、二元运算符</li>
<li>unary operators： 单目运算符、一元运算符</li>
</ul>
</li>
<li>parameter pattern: 参数模式</li>
<li>predicate: 谓词</li>
<li>prelude：预导入包</li>
<li>primitive type：原生类型</li>
<li>public: 公有、公有的</li>
<li>rang：区间（表示数据类型时用）</li>
<li>raw pointer： 裸指针</li>
<li>re-exported：重新导出的</li>
<li>re-exporting： 重导出</li>
<li>refer to： 指代、引用</li>
<li>referent：所指对象、引用对象</li>
<li>representation： 表示形式、表形
<ul>
<li>primitive representation： 原语表形</li>
</ul>
</li>
<li>safety：安全条款</li>
<li>separator： 分隔符</li>
<li>scrutinee： 检验对象表达式、检验对象</li>
<li>sign-extend：符号扩展</li>
<li>signal an error/warning：触发编译器报错/告警</li>
<li>size： 尺寸
<ul>
<li>sized：固定尺寸</li>
<li>unsized：非固定尺寸</li>
</ul>
</li>
<li>trait object：trait对象</li>
<li>str：字符串切片</li>
<li>
<ul>
<li>stringified： 字符串化</li>
</ul>
</li>
<li>subtrait：子trait</li>
<li>supertrait： 超类trait</li>
<li>symbol： 签名</li>
<li>syntax： 句法</li>
<li>terminate：结束</li>
<li>the lint check attributes： lint检查类属性</li>
<li>trait bounds: trait约束</li>
<li>transcriber： 转码器</li>
<li>type annotation：类型标注</li>
<li>unit-like struct：单元结构体</li>
<li>unit struct：单元结构体</li>
<li>unit tuple: 单元结构体</li>
<li>unreachable code ：执行不到的代码</li>
<li>unstable: 暂未稳定的</li>
<li>unwind： 展开</li>
<li>variant： 变体。指枚举或元组的变体</li>
<li>whitespace： 空白符</li>
<li>wrap: 包装
<ul>
<li>unwrap：解包</li>
</ul>
</li>
<li>zero-extend：零扩展</li>
<li>zero-sized： 零尺寸</li>
<li>zero-variant enums： 零变体枚举</li>
</ul>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        

                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                

                
            </nav>

        </div>

        

        

        

        
        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        

        

        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        
        
        <script type="text/javascript">
        window.addEventListener('load', function() {
            window.setTimeout(window.print, 100);
        });
        </script>
        
        

    </body>
</html>
